使用Anonymous类有什么危害? [英] What's the harm in using Anonymous class?

查看:116
本文介绍了使用Anonymous类有什么危害?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读问题的答案时出现了问题 - 如何做我在java中加入两个列表。此答案提供了解决方案

The question arose while reading a answer to this question - How do I join two lists in java. This answer gave the solution

List<String> newList = new ArrayList<String>() { { addAll(listOne); addAll(listTwo); } };

阅读评论时,用户表示这些评论是邪恶的,不应该用于制作。

Reading the comments, users said it was evil and ugly and should not be used in production.

我想知道使用它有什么害处?为什么在生产中使用它是丑陋的,邪恶的还是坏的?

I would like to know what's the harm in using this? Why is it ugly, evil or bad to use in production?

注意:被问到这是一个问题因为,帖子引用太旧了(2008)并且回答者已经离开几个月了。

Note: Asked it as a question because, the post referenced is too old (2008) and the answerer is away since several months.

推荐答案

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

Except for the already mentioned issues regarding good programming style and inheritance misuse, there is one more subtle problem - inner classes and (non-static) anonymous class instances act as closures. This means that they keep an implicit reference to the enclosing class instance. This can result in preventing of garbage collection and in the end, a memory leak.

给出一段示例源代码:

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 的新匿名子类创建一个类文件,它获得了一个所谓的合成字段,其中引用了的实例外类。生成的字节码大致相当于这样:

What happens at compilation time, is that the compiler creates a class file for the new anonymous subclass of Inner which gets a so-called synthetic field with the reference to the instance of the Outer class. The generated bytecode will be roughly equivalent to something like this:

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)列表。

Such capture of reference to the enclosing instance happens even for anonymous classes that never actually access any of methods or fields of the enclosing class, such as the double-brace initialized (DBI) list in your question.

这导致DBI列表保留对封闭实例的引用,只要它存在,从而防止封闭实例被垃圾回收。假设DBI列表恰好在应用程序中存在了很长时间,例如作为MVC模式中模型的一部分,并且捕获的封闭类例如是 JFrame ,这是一个有很多领域的大型班级。如果您创建了几个DBI列表,则会很快发生内存泄漏。

This results in the fact that the DBI list keeps a reference to the enclosing instance as long as it exists, preventing the enclosing instance from being garbage collected. Suppose the DBI list happens to live for a long time in the application, for example as a part of the model in MVC pattern, and the captured enclosing class is for example a JFrame, which is quite a large class with lots of fields. If you created a couple of DBI lists, you would get a memory leak very quickly.

一种可能的解决方案是仅在静态中使用DBI方法,因为在它们的范围内没有可用的封闭实例。

One possible solution would be using DBI only in static methods, because there is no such enclosing instance available in their scope.

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

On the other hand, I would still argue that using DBI is still not necessary in most cases. As for the list joining, I would create a simple reusable method, which is not only safer, but also more concise and clear.

public static <T> List<T> join(List<? extends T> first, List<? extends T> second) {
    List<T> joined = new ArrayList<>();
    joined.addAll(first);
    joined.addAll(second);
    return joined;
}

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

And then the client code becomes simply:

List<String> newList = join(listOne, listTwo);






进一步阅读:
https://stackoverflow.com/a/924536/1064809

这篇关于使用Anonymous类有什么危害?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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