1

请考虑以下两个类:

一个学生

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.) 学生演示

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

    }
}

根据oracle java 文档

为了创建内部类的实例,首先我们必须创建封闭类的实例,然后我们可以创建内部类的实例。

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

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

输出:

Yati
YNRHARYANA
YNRHARYANA
4

4 回答 4

7

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

除此之外:GC 甚至无法收集您的对象;因为adr仍然引用了“内部对象”;并且那个引用了它的外部所有者!

所以,即使你System.gc()在做之后添加一个调用obj = null......那个对象也不能被收集。(仅作记录:调用gc()只是 JVM 运行垃圾收集器的“提示”;不能保证会发生任何事情)

长话短说:当然,事情必须以这种方式进行。您的代码包含对内部对象的引用;虽然该引用存在,但该对象必须存在。虽然那个内在的对象必须存在;它的外部父母也必须如此。换句话说:整个系统依赖于内部/外部对象生命周期紧密耦合的事实!

并给出你最后的评论 - 运行时应该如何知道这个内部对象可以与它的外部父对象一起为空?!您可能会调用inner上实际使用external.this的方法;然后什么,NullPointerException?!

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

于 2017-03-02T09:01:50.610 回答
3

除了对内部类的引用仍在使用之外,所有内部和外部类的恶作剧都是红鲱鱼。

事实仍然是写作

Foo f = new Foo();
f = null;

对于任何类Foo,只会导致创建的实例Foo安排进行垃圾收集。该对象不一定会立即销毁。

于 2017-03-02T09:04:14.613 回答
1

当一个对象不再引用它或在它参与的引用图中不再引用任何对象时,一个对象就有资格被销毁。两个简单的情况:

(o)一个“丢失”的对象

(o1) <- (o2)两个“丢失的”对象

在第二种情况下,如果您有参考,(o1)(o1)不会丢失,而是(o2)会丢失。

内部对象具有对其封闭外部对象的引用,并且由于您具有对内部对象的引用,因此存在对其外部对象的“活”引用。你有类似的东西:

(outer <- (inner) <-)----some reference

于 2017-03-02T09:09:36.550 回答
1

如果内存中不存在负责创建地址对象的对象

当然可以:它是从 引用的adr,并且adr是可访问的,所以它不能被垃圾收集。即使没有被引用,也不一定会立即收集。

于 2017-03-02T09:04:49.413 回答