简体   繁体   English

扩展接口与通过匿名类实例化

[英]Extending an Interface vs Instantiating via Anonymous Class

NOTE: I am aware that this is dangerously close to many other questions. NOTE:我知道这很危险地接近许多其他问题。 I haven't seen any, however, that do not pertain specifically to Android's OnClickListener interface. 不过,我还没有看到任何与Android的OnClickListener界面无关的东西。 I am asking in a general sense. 我在一般意义上问。

I understand the difference between instantiating an interface via an anonymous class... a la: 我了解通过匿名类实例化接口之间的区别... la:

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

};

... and extending the interface. ...并扩展接口。

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

}

But, other than the obvious benefits from interfaces such as OnClickListener is there a strong advantage to either option? 但是,除了从诸如OnClickListener界面中获得的明显好处OnClickListener ,这两种选择还有很大的优势吗?

I would think that extending it would be the obvious choice because you are already creating that object - no duplication of effort. 我认为扩展它将是显而易见的选择,因为您已经在创建该对象-无需重复工作。 Is this right? 这是正确的吗?

I am asking in a general sense but, as I am currently working with Runnable , if it has sees an advantage from either option I'd love to know. 我在一般意义上问,但是,正如我目前正在使用Runnable ,我是否想知道这两种选择是否都具有优势。

Well here is an example that shows the main differences. 好吧,这是一个显示主要差异的示例。 It's a little contrived but it's just to illustrate. 这有些人为的,但这只是为了说明。

Here is an anonymous version: 这是一个匿名版本:

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;
    }
}

Here is a nested version: 这是一个嵌套版本:

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);
        }
    }
}

So you can see the main differences are then: 因此,您可以看到主要区别如下:

  • An anonymous class is inner and it has an implicit reference to the enclosing instance. 匿名类是内部的,它具有对封闭实例的隐式引用。

In particular, in the above example, the PrintBuilder is leaked until the inner Runnable objects die. 特别是,在上面的示例中,PrintBuilder泄漏到内部Runnable对象死亡为止。 In the second example, the Runnable class is static so it doesn't have this problem. 在第二个示例中,Runnable类是静态的,因此它没有此问题。

  • Anonymous classes are a little bit shorter. 匿名类要短一些。

An anonymous class doesn't need fields and constructors because they are implicit. 匿名类不需要字段和构造函数,因为它们是隐式的。

  • Big difference in the way the code is organized. 代码的组织方式有很大的不同。

An anonymous class is declared where it's instantiated and this can be pretty destructive to the layout of the enclosing class if the anonymous class isn't very short. 匿名类在实例化的地方声明,并且如果匿名类不是很短,那么这可能对封闭类的布局造成破坏。 On the other hand if the anonymous class is short, the functional-like syntax is nice. 另一方面,如果匿名类很短,则类似函数的语法会很好。

Also all classes tend to grow and in my experience this can turn in to a smell when an anonymous class gets too big. 同样,所有班级都趋于增长,以我的经验,当匿名班级变得太大时,这会变成一种气味。 Anonymous classes are also much more difficult to refactor in to a top-level class. 匿名类也很难重构为顶级类。

The first snippet defines a class, without a name, that implements the Runnable interface (and instantiates that anonymous class). 第一个片段定义了一个没有名称的类,该类实现Runnable接口(并实例化该匿名类)。 The second one defines a class, with a name, that also implements the Runnable interface. 第二个定义一个带有名称的类,该类也实现Runnable接口。

There's no difference in terms of inheritance and interface implementation except the second class has a name and the first one doesn't. 在继承和接口实现方面没有任何区别,只是第二个类有一个名称,而第一个没有。

The second snippet allows multiple classes to instantiate the Runnable implementation, whereas the first one defines a class that is only known from its enclosing class. 第二个片段允许多个类实例化Runnable实现,而第一个片段定义了一个仅从其包含的类中知道的类。 Sometimes one is better, sometimes the other. 有时一个更好,有时另一个更好。

Both approaches are valid. 两种方法都是有效的。 Which one to use depends of your usage: 使用哪个取决于您的用法:

  • If you implement an interface inside another class, you will have access to protected and private methods of the parent class. 如果在另一个类中实现接口,则可以访问父类的受保护的方法和私有方法。
  • If you want to keep things separated and reuse the same implementation for this interface, creating a separate class is the way to go. 如果要使事物分开并为该接口重用相同的实现,则创建单独的类是可行的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM