【问题标题】:Extending an Interface vs Instantiating via Anonymous Class扩展接口与通过匿名类实例化
【发布时间】:2014-03-29 08:45:45
【问题描述】:

NOTE:我知道这与许多其他问题非常接近。但是,我还没有看到任何与 Android 的 OnClickListener 接口不相关的内容。我问的是一般意义上的。

我了解通过匿名类实例化接口之间的区别... 啦啦:

private final Runnable runnable = new Runnable() {
    @Override
    public void run() {
        draw();
    }

};

...并扩展接口。

public class ClassyClass implements Runnable {
    ...
    //do other cool stuff here
    ...
    @Override
    public void run() {
        draw();
    }
    ...
    //and more here
    ...

}

但是,除了 OnClickListener 这样的接口带来的明显好处之外,这两种选择是否还有很大的优势?

我认为扩展它是显而易见的选择,因为您已经在创建该对象 - 无需重复工作。是这样吗?

我问的是一般意义上的问题,但由于我目前正在与Runnable 合作,我很想知道它是否从任一选项中看到了优势。

【问题讨论】:

    标签: java interface runnable anonymous-class


    【解决方案1】:

    这里有一个显示主要区别的示例。这有点做作,但只是为了说明。

    这是一个匿名版本:

    class PrintBuilder {
        List<Runnable> printers = new LinkedList<>();
    
        List<Runnable> get() {
            return printers;
        }
    
        PrintBuilder add(final String line) {
            printers.add(new Runnable() {
                public void run() {
                    System.out.println(line);
                }
            });
    
            return this;
        }
    }
    

    这是一个嵌套版本:

    class PrintBuilder {
        List<Printer> printers = new LinkedList<>();
    
        PrintBuilder add(String line) {
            printers.add(new Printer(line));
            return this;
        }
    
        List<Printer> get() {
            return printers;
        }
    
        static class Printer implements Runnable {
            String line;
    
            Printer(String line) {
                this.line = line;
            }
    
            public void run() {
                System.out.println(line);
            }
        }
    }
    

    所以你可以看到主要的区别是:

    • 匿名类是内部的,它对封闭实例有一个隐式引用。

    特别是,在上面的例子中,PrintBuilder 被泄露,直到内部的 Runnable 对象死亡。在第二个例子中,Runnable 类是静态的,所以它没有这个问题。

    • 匿名类有点短。

    匿名类不需要字段和构造函数,因为它们是隐式的。

    • 代码组织方式的巨大差异。

    一个匿名类是在它被实例化的地方声明的,如果匿名类不是很短的话,这可能对封闭类的布局造成很大的破坏。另一方面,如果匿名类很短,则类似函数的语法很好。

    此外,所有课程都倾向于增长,根据我的经验,当匿名课程变得太大时,这可能会变成一种气味。匿名类也更难重构为顶级类。

    【讨论】:

    • 太棒了,谢谢。我很欣赏具体的利弊。最后一个问题。我有点明白了,我看到其他人谈论过这个泄漏(在前 1 中),但你能具体解释一下它为什么会发生吗?
    • @BrassApparatus:这是因为,按照设计,内部类对其封闭对象具有隐式引用,以便能够访问它们的字段和方法。就像您在第二个示例的打印机中有一个 PrintBuilder 字段,并将 this 作为打印机构造函数的参数传递。
    • @JBNizet Gotcha,谢谢。感谢所有帮助。
    • 正如@JBNizet 所说,这是所有内部类的正常方面,基本上是它们的重点。但是我之前已经看到它变成了泄漏,基本上一些菜单栏项使整个处置的窗口保持活动状态,因为我忘记分离侦听器。
    【解决方案2】:

    第一个 sn-p 定义了一个没有名称的类,它实现了 Runnable 接口(并实例化了该匿名类)。第二个定义了一个具有名称的类,该类也实现了 Runnable 接口。

    在继承和接口实现方面没有区别,除了第二个类有名字而第一个没有。

    第二个 sn-p 允许多个类实例化 Runnable 实现,而第一个定义一个仅从其封闭类中知道的类。有时一种更好,有时另一种更好。

    【讨论】:

      【解决方案3】:

      这两种方法都有效。使用哪一个取决于您的使用情况:

      • 如果您在另一个类中实现接口,您将可以访问父类的受保护和私有方法。
      • 如果您希望将事物分开并为此接口重用相同的实现,则可以创建一个单独的类。

      【讨论】:

        猜你喜欢
        • 2021-04-27
        • 1970-01-01
        • 1970-01-01
        • 2019-01-06
        • 1970-01-01
        • 1970-01-01
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多