请考虑以下两个类:
一个学生
package datatypes;
public class Student {
private String name ;
public Student(String name) {
this.name = name;
}
class Address{
String city;
String state;
Address(String city , String state){
this.city = city;
this.state = state;
}
String getAddress(){
return city + state;
}
}
String getName(){
return name;
}
}
b。)StudentDemo
package datatypes;
import datatypes.Student.Address;
public class StudentDemo {
public static void main(String[] args) {
Student obj = new Student("Yati");
Address adr = obj.new Address("YNR" , "HARYANA");
System.out.println(obj.getName());
System.out.println(adr.getAddress());
obj=null;
//System.out.println(obj.getName());
System.out.println(adr.getAddress()); //Line 16
}
}
首先,我们必须创建一个封闭类的实例,然后创建内部类的实例。
与其他成员(实例变量和实例方法)一样,内部类也是外部类的实例的成员。在StudentDemo.java的第16行中,即使负责创建Address对象的对象在内存中不存在,我仍然能够打印地址的值。
我的问题是:为什么Address对象保留在内存中并且一旦obj设置为null就不会自动销毁?
输出:
Yati
YNRHARYANA
YNRHARYANA
将引用设置为null并不意味着垃圾收集器会立即从内存中收集相应的对象!
除此之外:GC甚至无法收集您的物品;因为adr
仍然提到“内在对象”;那个人提到了它的外部所有者!
所以,即使你在做System.gc()
后添加一个obj = null
调用......也无法收集该对象。 (并且只是为了记录:调用gc()
只是JVM的一个“提示”来运行垃圾收集器;不能保证发生任何事情)
长话短说:当然事情必须以这种方式运作。您的代码包含对内部对象的引用;虽然那个引用存在,但该对象必须存在。而那个内在的对象必须存在;它的外部父母也必须如此。换句话说:整个系统依赖于内/外物体的寿命紧密耦合的事实!
并且给出了你的最后一条评论 - 运行时如何知道这个内部对象可以与其外部父对象一起生活?!你可以在内部调用一个实际使用outer.this的方法;什么,NullPointerException?!
所以真正的答案可能是要明白你提出一个纯粹的理论问题。在“真实”世界中,你根本就不会这样做。在现实世界中,你不会分发对内部对象的引用;不关心他们的外在父母。与域驱动设计类似 - 对象的聚合也只能通过聚合的根对象接受(例如,参见here)。这当然与JVM中的对象不同;但正如所说的那样:一个例子,出于概念上的原因你只是做不同的事情。
除了你的内部阶级的引用仍然在使用之外,你所有的内外诡计都是红色的鲱鱼。
事实仍然是写作
Foo f = new Foo();
f = null;
对于任何类Foo
,只会导致创建的Foo
实例被安排进行垃圾回收。该对象不一定会立即销毁。
当一个对象没有更多的引用或者没有对它参与的引用图中的任何对象的引用时,它就有资格进行破坏。两个简单的例子:
(o)
一个“迷失”的对象
(o1) <- (o2)
两个“丢失”的对象“
在第二种情况下,如果你有(o1)
的参考,那么(o1)
不会丢失,但(o2)
是。
内部对象具有对其外部对象的引用,并且当您具有对内部对象的引用时,则存在对其外部对象的“活动”引用。你有类似的东西:
(outer <- (inner) <-)----some reference
如果负责创建Address对象的对象在内存中不存在
当然它确实如此:它是从adr
引用的,并且adr
是可访问的,因此它不能被垃圾收集。即使没有引用它,也不一定立即收集。