做匿名类*总是*保持对其封装实例的引用? [英] Do anonymous classes *always* maintain a reference to their enclosing instance?

查看:104
本文介绍了做匿名类*总是*保持对其封装实例的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一些代码,其中一个对象foo正在创建另一个
对象bar,并向它传递一个 Callable 。在此foo将返回
bar,然后我希望foo变得无法访问(即:可用于
垃圾回收)。



我最初的想法只是以匿名方式创建 Callable 。例如:

  class Foo {
...

public bar createBar(){
final int arg1 = ...
final int arg2 = ...
final int arg3 = ...
return new Callable< Baz>(){
@Override
public Baz call(){
return new Baz(arg1,arg2,arg3);
}
};


$ / code>

我想到这可能实际上不起作用但是,
作为内部类通常会保留对其封闭对象的引用。
我不想在这里引用封闭类,因为我希望封闭对象被
收集,而 Callable 仍然可到达。

另一方面,
检测到封闭实例永远不会真正引用
应该是非常简单的,所以也许Java编译器是智能的足够的
在这种情况下不包括引用。

所以...一个匿名内部类的实例会保存到
引用到它的封闭实例,即使它从未真正使用
封闭实例引用?

解决方案

是的,匿名内部实例类保持对其封闭实例的
引用,即使这些引用是从未实际使用过的
也是如此。此代码:

  public class Outer {
public Runnable getRunnable(){
return new Runnable() {
public void run(){
System.out.println(hello);
}
};




当使用 javac 生成两个类文件, Outer.class
Outer $ 1.class 。使用> javap -c 拆分后者,匿名内部类
产生:

 从Outer.java编译
类Outer $ 1 extends this java.lang.Object implements java.lang.Runnable {
final Outer this $ 0;

外部$ 1(外部);
代码:
0:aload_0
1:aload_1
2:putfield#1; // Field this $ 0:LOuter;
5:aload_0
6:invokespecial#2; //方法java / lang / Object。< init>:()V
9:return

public void run();
代码:
0:getstatic#3; // Field java / lang / System.out:Ljava / io / PrintStream;
3:ldc#4; // String hello
5:invokevirtual#5; //方法java / io / PrintStream.println:(Ljava / lang / String;)V
8:返回

}

putfield 行显示对封闭实例的引用是
被存储在字段这个$ 0 (类型 Outer )的构造函数
,即使这个字段永远不会再被使用。 p>

如果您试图使用匿名内部类创建小型潜在的
长期对象,这是不幸的,因为它们将保留在
中大)封闭的实例。解决方法是使用静态类(或顶级类)的实例。这不幸的是更详细。


I'm working with some code where one object, "foo", is creating another object, "bar", and passing it a Callable. After this foo will return bar, and then I want foo to become unreachable (ie: available for garbage collection).

My initial thought was to just create the Callable anonymously. eg:

class Foo {
  ...

  public Bar createBar() {
    final int arg1 = ...
    final int arg2 = ...
    final int arg3 = ...
    return new Callable<Baz>() {
      @Override
      public Baz call() {
        return new Baz(arg1, arg2, arg3);
      }
    };
  }
}

It occurred to me that this might not actually work as desired, however, as an inner class typically keeps a reference to its enclosing object. I don't want a reference to the enclosing class here, because I want the enclosing object to be collected while the Callable is still reachable.

On the other hand, detecting that the enclosing instance is never actually referred to should be pretty trivial, so perhaps the Java compiler is smart enough to not include a reference in that case.

So... will an instance of an anonymous inner class hold on to a reference to its enclosing instance even if it never actually uses the enclosing instance reference?

解决方案

Yes, instances of anonymous inner classes hold on to a reference to their enclosing instances even if these references are never actually used. This code:

public class Outer {
  public Runnable getRunnable() {
    return new Runnable() {
      public void run() {
        System.out.println("hello");
      }
    };
  }
}

When compiled with javac generates two class files, Outer.class and Outer$1.class. Disassembling the latter, the anonymous inner class, with javap -c yields:

Compiled from "Outer.java"
class Outer$1 extends java.lang.Object implements java.lang.Runnable{
final Outer this$0;

Outer$1(Outer);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #1; //Field this$0:LOuter;
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
   9:   return

public void run();
  Code:
   0:   getstatic       #3; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #4; //String hello
   5:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

}

The putfield line shows that a reference to the enclosing instance is being stored in the field this$0 (of type Outer) by the constructor even though this field is never used again.

This is unfortunate if you're attempting to create small potentially long-lived objects with anonymous inner classes as they'll hold onto the (potentially large) enclosing instance. A workaround is to use an instance of a static class (or a top-level class) instead. This is unfortunately more verbose.

这篇关于做匿名类*总是*保持对其封装实例的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆