为什么内部类实例会在内存中进行remian,即使外部类对象被销毁了?

Yat*_*ney 1 java garbage-collection inner-classes local-class

请考虑以下两个类:

一个学生

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

    }
}
Run Code Online (Sandbox Code Playgroud)

根据oracle java docs

首先,我们必须创建一个封闭类的实例,然后创建内部类的实例.

与其他成员(实例变量和实例方法)一样,内部类也是外部类的实例的成员.在StudentDemo.java的第16行中,即使负责创建Address对象的对象在内存中不存在,我仍然能够打印地址的值.

我的问题是:为什么Address对象保留在内存中并且一旦obj设置为null 就不会自动销毁?

输出:

Yati
YNRHARYANA
YNRHARYANA
Run Code Online (Sandbox Code Playgroud)

Gho*_*ica 7

将引用设置为null并不意味着垃圾收集器会立即从内存中收集相应的对象!

除此之外:GC甚至无法收集您的物品; 因为adr还有对"内在对象"的引用; 那个人提到了它的外部所有者!

所以,即使你System.gc()在做完之后添加一个电话obj = null......也无法收集该对象.(并且仅用于记录:调用gc()只是JVM的"提示"以运行垃圾收集器;无法保证发生任何事情)

长话短说:当然事情必须以这种方式运作.您的代码包含对内部对象的引用; 虽然那个引用存在,但该对象必须存在.而那个内在的对象必须存在; 它的外部父母也必须如此.换句话说:整个系统依赖这样的事实:内/外对象的生命时间是紧耦合!

并且考虑到你的最后一条评论 - 运行时如何知道这个内部对象可以与其外部父对象一起生活?!你可以在内部调用一个实际使用outer.this的方法 ; 什么,NullPointerException?!

所以真正的答案可能是要明白你提出一个纯粹的理论问题.在"真实"世界中,你根本就不会这样做.在现实世界中,你不会分发对内部对象的引用; 不关心他们的外在父母.与域驱动设计类似 - 对象的聚合也只能通过聚合的根对象接受(参见此处).这当然与JVM中的对象不同; 但正如所说的那样:一个例子,出于概念上的原因你只是做不同的事情.