java 匿名类 优缺点_java – 使用匿名类有什么危害?

除了已经提到的关于良好的编程风格和继承滥用的问题,还有一个微妙的问题 – 内部类和(非静态)匿名类实例充当闭包。这意味着它们保留对包含类实例的隐式引用。这可以导致防止垃圾收集,并最终导致内存泄漏。

给出一个示例源代码段:

public interface Inner {

void innerAction();

}

public class Outer {

public void methodInOuter() {}

private Inner inner = new Inner() {

public void innerAction() {

// calling a method outside of scope of this anonymous class

methodInOuter();

}

}

}

编译时会发生什么,是编译器为Inner的新的匿名子类创建一个类文件,它获得一个所谓的合成字段,引用Outer类的实例。生成的字节码大致相当于这样:

public class Outer$1 implements Inner {

private final Outer outer; // synthetic reference to enclosing instance

public Outer$1(Outer outer) {

this.outer = outer;

}

public void innerAction() {

// the method outside of scope is called through the reference to Outer

outer.methodInOuter();

}

}

即使对于从不实际访问任何方法或包含类的字段(例如问题中的双括号初始化(DBI)列表)的匿名类,也捕获对包含实例的引用。

这导致以下事实:DBI列表保持对包围实例的引用,只要它存在,防止封闭实例被垃圾收集。假设DBI列表恰好在应用程序中存在很长时间,例如作为MVC模式中的模型的一部分,并且捕获的封闭类是例如JFrame,这是具有大量字段的相当大的类。如果你创建了几个DBI列表,你会很快得到内存泄漏。

一个可能的解决方案是仅在静态方法中使用DBI,因为在它们的作用域中没有这样的封闭实例。

另一方面,我仍然认为在大多数情况下使用DBI仍然没有必要。至于列表加入,我会创建一个简单的可重用的方法,这不仅更安全,而且更简洁明了。

public static List join(List extends T> first, List extends T> second) {

List joined = new ArrayList<>();

joined.addAll(first);

joined.addAll(second);

return joined;

}

然后客户端代码变得简单:

List newList = join(listOne, listTwo);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值