了解Java接口原理

时间:2014-09-26 09:33:24

标签: java interface extends subclassing class-hierarchy

我正在阅读一本Java书,并且这次再次考虑这个段落实际意味着什么:

  

接口旨在支持运行时的动态方法解析。通常,为了从一个类调用方法到另一个类,两个类都需要在编译时出现,因此Java编译器可以检查以确保方法签名是兼容的。这个要求本身就是一个静态和不可扩展的分类环境。在这样的系统中,不可避免地会在类层次结构中将功能提升得越来越高,以便机制可用于越来越多的子类。接口旨在避免此问题。它们将方法或方法集的定义与继承层次结构断开连接。由于接口与类的层次结构不同,因此在类层次结构方面不相关的类可能实现相同的接口。这就是实现接口真正功能的地方。

第一个问题:作者在说from one class to another时的意思是什么?他是否意味着这些类在层次结构方面是相关的?我的意思是,将子类对象引用分配给它的超类类型变量,然后调用方法?

第二个问题:作者再次说This requirement by itself makes for a static and nonextensible classing environment是什么意思?我不明白makes for的含义(英语不是我的主要语言)以及环境被称为静态和不可扩展的原因。

第三个问题:他说functionality gets pushed up higher and higher是什么意思?为什么它会越来越高?什么功能?另外,mechanisms will be available to more and more subclasses.有哪些机制?方法

第四个问题:Interfaces are designed to avoid this problem。什么问题???

我知道答案必须明显,但我不知道。也许主要是因为我没有看到一些神奇的英语短语。请帮助我理解这一段的内容。

2 个答案:

答案 0 :(得分:5)

  1. 在任何两个班级之间。例如,如果您的代码包含对String.substring()的调用,则String类及其substring()方法必须在编译时可用。
  2. 如上所述,“make for”意思与“创造”相同。环境是不可扩展的,因为您可能想要使用的所有内容都必须在编译时可用。 (但这并非100%正确。即使没有接口,抽象类和方法也提供了扩展点,但它们并不像我们将要看到的那样灵活。)
  3. 想象一下,您有两个班级:FooBar。这两个类都扩展了类Thingy。但是,您想要添加一个新功能,假设您希望在网页上以HTML格式显示。所以你要为这两个方法添加一个方法。
  4. 基本问题

      abstract class Thingy { ... }
    
      class Foo extends Thingy {
         ...
         public String toHTMLString() {
            ...
         }
      }
    
      class Bar extends Thingy {
         ...
         public String toHTMLString() {
            ...
         }
      }
    

    这很棒,但你怎么称呼这种方法?

     public String createWebPage( Thingy th ) {
        ...
        if (th instanceof Foo)
           return ((Foo)th).toHTMLString();
        if (th instanceof Bar)
           return ((Bar)th).toHTMLString();
        ...
     }
    

    显然,这种方式根本不灵活。所以,你可以做什么?好吧,你可以将toHTMLString()推到他们共同的祖先Thingy。 (这就是本书所讨论的内容。)

    解决它的天真尝试

      abstract class Thingy {
         ...
         public abstract String toHTMLString();
      }
    
      class Foo extends Thingy {
         ...
         public String toHTMLString() {
            ...
         }
      }
    
      class Bar extends Thingy {
         ...
         public String toHTMLString() {
            ...
         }
      }
    

    然后你可以这样称呼它:

     public String createWebPage( Thingy th ) {
        ...
        return th.toHTMLString();
     }
    

    成功!除了现在你已经强制每个扩展Thingy的类实现toHTMLString()方法,即使它对其中一些方法没有意义。更糟糕的是,如果这两个对象没有明确地扩展,那么它们是完全无关的呢?你必须将方法一直推到他们的共同祖先,即java.lang.Object。而你不能这样做。

    带接口的解决方案

    那么我们可以用接口做什么呢?

      abstract class Thingy { ... }
    
      interface HTMLPrintable {
         public String toHTMLString();
      }         
    
      class Foo extends Thingy implements HTMLPrintable {
         ...
         public String toHTMLString() {
            ...
         }
      }
    
      class Bar extends Thingy implements HTMLPrintable {
         ...
         public String toHTMLString() {
            ...
         }
      }
    
      //We've added another class that isn't related to all of the above but is still HTMLPrintable,
      //with interfaces we can do this.
      class NotEvenAThingy implements HTMLPrintable { 
         public String toHTMLString() {
            ...
         }
      }     
    

    调用代码只是

     public String createWebPage( HTMLPrintable th ) {
        ...
        return th.toHTMLString(); // "implements HTMLPrintable" guarantees that this method exists
     }
    

    那么接口是什么?

    有许多隐喻用于理解界面,最受欢迎的可能是契约的概念。对调用者说的是:“如果你需要完成X,我们就会完成它。不要担心怎么样,这不是你的问题。” (虽然“合同”一词通常用于更一般的意义,但要小心。)

    或者换句话说:如果你想买一份报纸,你不在乎它是在超市,报刊经销商或街上的小摊位出售,你只想买报纸。因此,NewspaperVendor在这种情况下是一个具有一种方法的接口:sellNewsPaper()。如果有人后来决定在网上或门到门销售报纸,他们所需要做的只是实现界面,人们会从他们那里购买。

    但我最喜欢的例子是商店橱窗里的小贴纸上写着“我们接受X,Y和Z信用卡”。这是界面最纯粹的现实世界的例子。商店可以出售任何东西(它们甚至可能不是商店,有些可能是餐馆),他们使用的读卡器也不同。但是你不关心所有这些,你看看标志,你知道你可以用你的卡支付。

答案 1 :(得分:1)

段落的关键是"类需要在编译时出现"第2行。课程更具体。接口是抽象的。

由于类是具体的,因此设计人员和程序员需要了解所有关于类结构和如何实现方法。接口更抽象的地方。 (它们仅包含抽象方法)。因此,程序员只需知道接口必须具有哪些方法以及这些方法的签名。他不需要详细了解这些是如何实施的。

因此,在创建子类时,使用接口更容易,更好。您只需要知道接口的方法签名。

使用具体类我们必须实现类层次结构中高级方法的功能,同时使用接口可以避免这个问题。 (有一个相关的多态性概念,你可能会在以后学习)