请考虑以下两个课程:
a。)学生
sub_list_a, sub_list_b = map(list, zip(*filter(all, zip(a, b))))
b。)StudentDemo
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;
}
}
首先要创建内部类的实例,我们必须创建一个封闭类的实例,然后我们可以创建内部类的实例。
与其他成员(实例变量和实例方法)一样,内部类也是外部类实例的成员。在StudentDemo.java的第16行中,我仍然能够打印地址的值,即使负责创建地址对象的对象也是如此NOT 存在于内存中。
我的问题是:为什么Address对象保留在内存中,并且在 obj 设置为null后不会自动销毁?
输出:
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
}
}
答案 0 :(得分:6)
设置对 null 的引用并不意味着垃圾收集器会立即从内存中收集相应的对象!
除此之外:GC甚至无法收集您的物品;因为adr
仍然引用了"内部对象&#34 ;;那个人提到了它的外部所有者!
因此,即使您在执行System.gc()
之后添加obj = null
电话,该对象也可以 收集。 (并且只是为了记录:调用gc()
只是一个"提示"到JVM运行垃圾收集器;不能保证发生任何事情)
长话短说:当然事情必须以这种方式运作。您的代码包含对内部对象的引用;虽然那个引用存在,但该对象必须存在。而内部对象必须存在;所以它的外部父级必须如此。换句话说:整个系统依赖来确定内/外物体的生命时间紧密耦合!
并且鉴于你的最后评论 - 运行时如何知道这个内部对象可以使用其外部父项为空?您可以在 inner 上调用实际使用 outer.this 的方法;然后是什么,NullPointerException?!
所以真正的答案可能是要明白你提出一个纯粹的理论问题。在"真实"世界你根本就不会这样做。在现实世界中,你不会分发对内部对象的引用;不关心他们的外在父母。与域驱动设计类似 - 对象的聚合也仅通过聚合的 root 对象接受(请参阅here例如)。这当然与JVM中的对象不同;但正如所说:一个例子,你只是为概念原因做了不同的事情。
答案 1 :(得分:3)
除了你的内部类的引用仍在使用之外,你所有的内外诡计都是红色的鲱鱼。
事实仍然是写作
Foo f = new Foo();
f = null;
对于任何类Foo
,只会导致创建的Foo
实例已安排进行垃圾回收。该对象不一定会被立即销毁。
答案 2 :(得分:1)
如果负责创建Address对象的对象在内存中不存在
当然可以:它来自adr
,adr
是可访问的,因此无法进行垃圾回收。即使没有引用,也不一定立即收集。
答案 3 :(得分:1)
当一个对象没有更多的引用或者没有对它参与的引用图中的任何对象的引用时,它就有资格进行破坏。两个简单的例子:
(o)
一个“迷失”的对象
(o1) <- (o2)
两个“丢失”的对象“
在第二种情况下,如果您在(o1)
上有引用,那么(o1)
不会丢失,但(o2)
是。
内部对象具有对其外部对象的引用,并且当您具有对内部对象的引用时,则存在对其外部对象的“活动”引用。你有类似的东西:
(outer <- (inner) <-)----some reference