Java电梯模拟程序重复输出finalize()内容的原因咨询
电梯模拟程序finalize()方法额外输出问题
我正在编写一个模拟电梯随机遍历不同楼层数建筑的程序,需要使用finalize()方法在每个建筑结束后执行清理操作,并且在特定楼层触发object = null和System.gc()。
public class ElevatorTwo { static double elev; double floor = 0; String next; ElevatorTwo(double n) { floor = n; } ElevatorTwo() { next = "The next building has "; } public void finalize() { System.out.println("Elevator Ending, elevator returned to the first floor."); System.out.println(); } public static void buildingOne() { ElevatorTwo buildOne = new ElevatorTwo(10); System.out.println("This building has 10 stories."); try { for (int i = 0; i < buildOne.floor; i++) { elev = (int) (Math.random() * buildOne.floor) + 1; // if (elev == i) // elev = i + elev; try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println(e); } System.out.printf("Floor %2.0f%n", elev); if (elev == 2 || elev == 4 || elev == 8) { buildOne = null; { System.gc(); } } } } catch (NullPointerException e) { } } public static void buildingTwo() { ElevatorTwo buildTwo = new ElevatorTwo(15); ElevatorTwo myBuildTwo = new ElevatorTwo(); System.out.println(myBuildTwo.next + (int) buildTwo.floor + " stories."); try { for (int i = 0; i < buildTwo.floor; i++) { elev = (int) (Math.random() * buildTwo.floor) + 1; // if (elev == i) // elev = i + elev; try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println(e); } System.out.printf("Floor %2.0f%n", elev); if (elev == 2 || elev == 4 || elev == 8) { buildTwo = null; { System.gc(); } } } } catch (NullPointerException nul) { } } public static void buildingThree() { ElevatorTwo buildThree = new ElevatorTwo(30); ElevatorTwo myBuildThree = new ElevatorTwo(); System.out.println(myBuildThree.next + (int) buildThree.floor + " stories."); try { for (int i = 0; i < buildThree.floor; i++) { elev = (int) (Math.random() * buildThree.floor) + 1; // if (elev == i) // elev = i + elev; try { Thread.sleep(500); } catch (InterruptedException e) { System.out.println(e); } System.out.printf("Floor %2.0f%n", elev); if (elev == 8 || elev == 13 || elev == 17 || elev == 20 || elev == 25 || elev == 28) { buildThree = null; { System.gc(); } } } } catch (NullPointerException e) { } } public static void main(String[] args) { System.out.println(); buildingOne(); buildingTwo(); buildingThree(); } }
运行结果示例
This building has 10 stories. Floor 7 Floor 3 Floor 3 Floor 5 Floor 4 Elevator Ending, elevator returned to the first floor. The next building has 15 stories. Floor 14 Floor 5 Floor 3 Floor 11 Floor 8 Elevator Ending, elevator returned to the first floor. The next building has 30 stories. Floor 12 Floor 17 Elevator Ending, elevator returned to the first floor. Elevator Ending, elevator returned to the first floor.
技术问询
当调用buildingOne()、buildingTwo()、buildingThree()三个方法时,为何会额外多输出一次“Elevator Ending, elevator returned to the first floor.”语句?而仅调用buildingOne()和buildingTwo()时则无此重复输出现象。
问题原因及解释
额外的输出是因为未被显式回收的ElevatorTwo实例在程序结束时被JVM自动回收,触发了finalize()方法。
具体拆解:
- 每个
buildingX()方法里都创建了两个ElevatorTwo实例:比如buildingTwo()里的buildTwo(带楼层参数)和myBuildTwo(无参),buildingThree()同理。 - 触发特定楼层时,你只把
buildX设为null并调用System.gc(),但**myBuildTwo、myBuildThree这些无参实例从未被显式置为null**,它们的生命周期会持续到方法执行完毕,甚至到程序结束。 - 调用三个方法时,程序结束前JVM会触发全局垃圾回收,回收所有剩余的未引用实例(比如
buildingTwo里的myBuildTwo、buildingThree里的myBuildThree,或者之前未被及时回收的实例),每回收一个就会执行一次finalize(),因此多了一次输出。 - 仅调用前两个方法时,JVM可能在程序结束前没有触发这次全局回收,或者剩余实例的
finalize()未被执行(finalize()的执行时机完全由JVM控制,不保证一定会执行),所以没有额外输出。
另外需要注意:finalize()方法已在Java 9中标记为过时,且执行时机不可控,非常不适合用来做资源清理操作。如果需要清理资源,推荐使用try-with-resources语法或者显式的清理方法。
内容的提问来源于stack exchange,提问作者old new coder guy
相关产品推荐
相关产品推荐

