【问题标题】:Setting outer class instance to null, and yet inner class instances is able to access outer class's field. How?将外部类实例设置为空,而内部类实例能够访问外部类的字段。如何?
【发布时间】:2015-02-04 08:20:00
【问题描述】:

考虑以下代码:

class OuterClass{
    String ocs="ocs";
    class InnerClass{
        String ics="ics";
        void innerMeth(){
            System.out.println(ocs);
        }
    }
}
//main class
public class HelloWorld{
    public static void main(String []args){
        OuterClass ob=new OuterClass();
        OuterClass.InnerClass ob1=ob.new InnerClass();
        ob=null;
        ob1.innerMeth();
    }
}

仍然打印出字符串 'ocs' 。
基本上即使我已将OuterClass 实例设置为空。
InnerClass 实例仍然可以访问OuterClass 引用的字段ocs
如何 ?

这与闭包有关吗?即,即使在上下文不再存在之后,也可以在上下文中维护变量,在这种情况下是 OuterClass 对象。

【问题讨论】:

  • 实例不能为空。这不是一个存在的概念。变量可以存储值null。这不会影响对对象的任何其他引用。

标签: java nested closures inner-classes


【解决方案1】:

InnerClass 在创建时将它自己对外部类的引用。如果您对外部类的引用为空,则这与内部类维护的引用无关。见the java language ref

类 O 的直接内部类 C 的实例 i 与 O 的实例相关联,称为 i 的直接封闭实例。对象的直接封闭实例(如果有)在创建对象时确定(第 15.9.2 节)。

【讨论】:

    【解决方案2】:

    您要更新的只是对实例的引用,而不是实例本身。引用只是指向其他事物的事物。

    可以将其想象为您手机中的联系人 - 您存储了朋友的电话号码,以便您可以拨打他们的电话;从您的联系人中删除他们的号码不会使他们的手机消失。

    【讨论】:

    • 嗯,是的,记住“引用变量”==“实例”本身很重要!
    【解决方案3】:

    在每个类中添加finalize()方法会更好地理解。

     class OuterClass {
        protected void finalize() throws Throwable {
            System.out.println("oc instance finalized..");
        };
        String ocs = "ocs";
    
    class InnerClass {
        String ics = "ics";
    
        protected void finalize() throws Throwable {
            System.out.println("IC instance finalized");
        };
    
        void innerMeth() {
            System.out.println(ocs);
        }
    }
    

    }

    // main class
    class HelloWorld {
        public static void main(String[] args) {
            OuterClass ob = new OuterClass();
            OuterClass.InnerClass ob1 = ob.new InnerClass();
            ob = null;
            // ob1=null;
            System.gc();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ob1.innerMeth(); // you will get NPE here
        }
    }
    

    当只有ob 设置为null 时,ob1 仍然有对它的引用,所以它不会被最终确定,因此仍然可以访问。

    如果您将obob1 设置为null,则输出将为:

     IC instance finalized
    oc instance finalized..
    Exception in thread "main" java.lang.NullPointerException
        at HelloWorld.main
    

    因为不会引用obob1,因此两个对象都是finalized。请注意,设置为 null 的是 reference。其他引用可能仍与 ob 一起指向该对象(在您的情况下为 ob1

    【讨论】:

    • 我们有时都会有这样的时刻 :)
    猜你喜欢
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    • 1970-01-01
    • 2016-01-21
    相关资源
    最近更新 更多