【问题标题】:Why do we use the "new" keyword with an Interface in Java?为什么我们在 Java 的接口中使用“new”关键字?
【发布时间】:2013-03-16 12:13:52
【问题描述】:

我是 Android 新手。我在基本的面向对象编程课程中学习过接口为类提供了一种增强其功能的方法。真正以这种方式增强其功能的类,实现这些接口并覆盖所有用接口编写的方法。

以下代码在 Android 中执行相同的工作:

public class MyActivity extends Activity implements OnClickListener {
   // All other code you may expect

   myButton.setOnClickListener(this);

   @override
   public onClick(View view) {
      // Code when view is clicked
   }
} 

这段代码是可以理解的。但是下面的代码对我来说毫无意义,我在不同的地方搜索过,但没有得到满意的答案。

public class MyActivity extends Activity {
   // All other code you may expect

   myButton.setOnClickListener(new OnClickListner() {

      @override
      public onClick(View view) {
         // Code when view is clicked
      }
  });
}

现在,OnClickListener() 是 Android 文档中所说的接口,现在我们正在实例化一个接口。不是只实现接口吗?请帮助我理解这一点。

【问题讨论】:

    标签: java android oop


    【解决方案1】:

    new OnClickListner() { 没有实例化一个接口,它是在声明一个anonymous inner class。基本上是一个匿名类(实现接口 OnClickListner 的类),它本身没有名称。

    来自Documentation

    匿名类表达式包含以下内容:

    • 新的运算符
    • 要实现的接口或要扩展的类的名称。在本例中,匿名类实现了 OnClickListner 接口。
    • 包含构造函数参数的括号,就像普通的类实例创建表达式一样。注意:在实现接口的情况下,没有构造函数,因此您使用一对空括号,如本例所示。
    • 主体,即类声明主体。更具体地说,在正文中,允许方法声明,但不允许声明。

    【讨论】:

    • 正如 java doc 所说,“匿名类可以让你的代码更简洁。它们可以让你同时声明和实例化一个类。它们就像本地类,只是它们没有名称。如果您只需要使用一次本地类,请使用它们。” 这又与声明一个新类有关,但是 onClickListener()- 我们真的将其创建为一个新类吗?
    • @ArslanAli yepp,它基本上是在创建一个新的嵌套类(不是外部类)。如果签入字节码,内部类将被声明为Outerclassname$1 implements Interface name
    • 谢谢 :) 现在看来,是符合 OOP 规则的。
    • 好吧,我可以换个说法吗? new OnClickListener 表示新建一个类,但是这个类的名字不是OnClickListener。相反,类的名称是隐藏的,但无论类是什么,有一点可以肯定,它实现了 OnClickListener。 new HiddenNameClass implements OnClickListener 本来是如果 java 没有为我们提供匿名内部类的工具。是你想要解释的吗?
    【解决方案2】:

    那些 OnClickListener 是匿名类。方括号包括类定义。

    【讨论】:

    • 括号中包含类定义意味着我们正在另一个类中创建一个新类?如果是这样,那为什么我们要强制重写其中的onClick() 方法呢?
    • 好吧,我可以换个说法吗? new OnClickListener 表示新建一个类,但是这个类的名字不是OnClickListener。相反,该类的名称是隐藏的,但无论该类是什么,有一点是肯定的,它实现了 OnClickListener。 new HiddenNameClass implements OnClickListener 本来是如果 java 没有为我们提供匿名内部类的工具。是你想要解释的吗?
    • 是的。如果查看类文件,类名最终会类似于 MyActivity$_1 ,其中 _1 是生成的类名。
    【解决方案3】:

    如果您将 new 与接口一起使用,则必须在创建实现接口但没有自己名称的 anonymous inner class 时覆盖 { } 块中接口提供的方法。

    这允许您拥有多个不同的点击处理程序,而无需为每个按钮创建一个实现 OnClickListner 的类。

    【讨论】:

      【解决方案4】:

      实际上,这是我在 OOP 中见过的最糟糕的做法之一,而不仅仅是 java。

      基本上,您从Interface 创建一个匿名内部类,并且您必须立即实现接口提供的所有方法。在这种情况下,将接口视为抽象类(基本上总是这样,或多或少)。

      虽然广泛传播,并得到一些语言的适当支持,但 java 仅在 语言 级别支持内部类的概念。 然而,在 字节码 级别上,没有内部类。编译器将这些内部类语言结构从它们的父类中分离出来,将它们作为兄弟姐妹放置在它们旁边,并带有一个 $ 符号和一个连续的数字,并将私有作用域元素(方法、变量)提升到包作用域。 现在让其沉思片刻,并考虑安全问题。

      接下来的事情是,这些匿名内部类在 Android 上下文中被过度使用(最初的问题被标记为 Android)完全弄乱了代码并使其完全不可读。这与 干净的代码 相去甚远,我强烈建议您遵循这一点,以维护易于阅读和维护的代码。

      另一件事是每个new Interface() { ... }; 自然地创建一个新对象。通常你会在 Android 世界的听众中看到这一点。如果您有多个侦听器,请为您自己和您的用户节省一些内存并使用开关实现一个对象...不要每次都创建一个新对象只是因为 Google 示例会这样做,并且因为有些人在此处回答时在他们的示例中这样做在 SO 和教程或论坛中。 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-23
        • 2017-08-04
        • 1970-01-01
        • 2014-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多