当前位置:  开发笔记 > 编程语言 > 正文

当从实例方法返回一个没有引用其封闭类的匿名类时,它会引用它.为什么?

如何解决《当从实例方法返回一个没有引用其封闭类的匿名类时,它会引用它.为什么?》经验,为你挑选了1个好方法。

当从实例方法返回没有引用其封闭类的匿名类时,它会引用this.为什么?

请考虑以下代码:

package so;

import java.lang.reflect.Field;

public class SOExample {

    private static Object getAnonymousClassFromStaticContext() {
        return new Object() {
        };
    }

    private Object getAnonymousClassFromInstanceContext() {
        return new Object() {
        };
    }

    public static void main(String[] args) throws NoSuchFieldException, SecurityException {

        Object anonymousClassFromStaticContext = getAnonymousClassFromStaticContext();
        Object anonymousClassFromInstanceContext = new SOExample().getAnonymousClassFromInstanceContext();

        Field[] fieldsFromAnonymousClassFromStaticContext = anonymousClassFromStaticContext.getClass().getDeclaredFields();
        Field[] fieldsFromAnonymousClassFromInstanceContext = anonymousClassFromInstanceContext.getClass().getDeclaredFields();

        System.out.println("Number of fields static context: " + fieldsFromAnonymousClassFromStaticContext.length);
        System.out.println("Number of fields instance context: " + fieldsFromAnonymousClassFromInstanceContext.length);
        System.out.println("Field from instance context: " + fieldsFromAnonymousClassFromInstanceContext[0]);

    }

}

这是输出:

Number of fields static context: 0
Number of fields instance context: 1
Field from instance context: final so.SOExample so.SOExample$2.this$0

每种方法虽然看似调用相同的代码,但却在做一些不同的事情.在我看来,实例方​​法返回一个嵌套类,而静态方法返回一个静态嵌套类(作为静态成员,它显然不能有引用this).

鉴于没有提及封闭类的事实,我看不出这方面的好处.

幕后发生了什么?



1> Matthias..:

匿名/内部类背后有一个设计原则:内部类的每个实例都属于外部类的实例.

抛弃对内部类的引用会改变垃圾收集的行为:它的实现方式,只要内部类存活,外部类就不能被垃圾收集.
这支持了在没有外部类的情况下内部类不能存在的想法.

应用程序可能依赖于此行为,例如通过创建临时文件并在析构函数中删除它.这样,只有当所有内部类都消失时才会删除该文件.

这也意味着无法更改当前行为,因为更改它可能会破坏现有应用程序.

因此,当您不需要引用时,应始终将内部类标记为静态,因为这可能会导致一些不错的内存泄漏.

编辑: 我想说的内容的例子(抱歉可怕的代码质量):

class Ideone
{
    static Object[] objects = new Object[2];

    public static void main (String[] args) throws java.lang.Exception
    {
        M1();
        M2();
        System.gc();
    }

    static void M1() {
        objects[0] = new Foo().Bar();
    }
    static void M2() {
        objects[1] = new Foo().Baz();
    }
}

class Foo {
    static int i = 0;
    int j = i++;

    public Foo() {
        System.out.println("Constructed: " + j);
    }

    Object Bar() {
        return new Object() {

        };
    }
    static Object Baz() {
        return new Object() {

        };
    }

    protected void finalize() throws Throwable {
        System.out.println("Garbage collected " + j);
    }
}

输出:

构造:0
构造:1
垃圾收集1

如您所见,第一个Foo 不是垃圾收集,因为仍然存在"内部实例".要使此行为起作用,内部类需要引用.

当然,这可能也有不同的实现.但我想说,保持参考是一个有目的的设计决策,因此"内部实例"不会比它的父母更活跃.

BTW:Java语言引用非常隐秘地说明了这一点(对于不访问外部类的内部类,没有例外):

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

推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有