public interface Imy {
}public class A implements Imy{
}public class B extends A implements Imy{
}
// 问一下此时B继承了A,但又重复了一次接口Imy,会不会有潜在问题???

解决方案 »

  1.   

    extends 上继承  因为他是一个简单的抽象  
      

  2.   

    不会有问题。
    因为,B extend A的时候,其实就相当于 implements lmy了,你后面加不加implements lmy,其实是一个样的。
    如果你不放心,就看看JDK里面的集合框架,里面几乎都是这么写:
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
    如果你还不放心,可以尝试以下代码:
    public static interface Imy {
    public void hi();
    } public static class A implements Imy{
    @Override
    public void hi() {
    }
    } public static class B extends A implements Imy{
    }
    public static void main(String[] args) {
    A a = new A();
    a.hi();
    B b = new B();
    b.hi();
    }
    然后对生成的App$Imy.class,App$A.class,App$B.class,App.class进行javap -c反编译,结果如下:
    App$Imy.class:Compiled from "App.java"
    public interface org.imzhs.learn.test.App$Imy{
    public abstract void hi();}这个没什么,就是一个接口里面有个hi方法,该方法时抽象的(接口的方法默认都是抽象方法)
    App$A.class:Compiled from "App.java"
    public class org.imzhs.learn.test.App$A extends java.lang.Object implements org.imzhs.learn.test.App$Imy{
    public org.imzhs.learn.test.App$A();
      Code:
       0:   aload_0
       1:   invokespecial   #10; //Method java/lang/Object."<init>":()V
       4:   returnpublic void hi();
      Code:
       0:   return}这里可以看到,A里面实现了Imy的hi方法
    App$B.class:Compiled from "App.java"
    Compiled from "App.java"
    public class org.imzhs.learn.test.App$B extends org.imzhs.learn.test.App$A implements org.imzhs.learn.test.App$Imy{
    public org.imzhs.learn.test.App$B();
      Code:
       0:   aload_0
       1:   invokespecial   #10; //Method org/imzhs/learn/test/App$A."<init>":()V
       4:   return}这里,继承了A,实现了Imy,但是B中并没有出现hi()方法,因为hi()方法已经在A中实现
    App.class:Compiled from "App.java"
    public class org.imzhs.learn.test.App extends java.lang.Object{
    public org.imzhs.learn.test.App();
      Code:
       0:   aload_0
       1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
       4:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   new     #16; //class org/imzhs/learn/test/App$A
       3:   dup
       4:   invokespecial   #18; //Method org/imzhs/learn/test/App$A."<init>":()V
       7:   astore_1
       8:   aload_1
       9:   invokevirtual   #19; //Method org/imzhs/learn/test/App$A.hi:()V
       12:  new     #22; //class org/imzhs/learn/test/App$B
       15:  dup
       16:  invokespecial   #24; //Method org/imzhs/learn/test/App$B."<init>":()V
       19:  astore_2
       20:  aload_2
       21:  invokevirtual   #25; //Method org/imzhs/learn/test/App$B.hi:()V
       24:  return}可以看到,APP.java中的main()方法,对于A,B中hi()的调用全部都是通过invokevirtual 进行,而invokevirtual会从当前对象开始,由下到上寻找hi()的实现,所以最终找到的都是A中的hi()方法
    那么,我们把Class B改成:public static class B extends A{
    }此时,B生成的字节码为:Compiled from "App.java"
    public class org.imzhs.learn.test.App$B extends org.imzhs.learn.test.App$A{
    public org.imzhs.learn.test.App$B();
      Code:
       0:   aload_0
       1:   invokespecial   #8; //Method org/imzhs/learn/test/App$A."<init>":()V
       4:   return}可以看到,除了类头部发生一点改变,其它都没有变化,那么APP.Class呢?Compiled from "App.java"
    public class org.imzhs.learn.test.App extends java.lang.Object{
    public org.imzhs.learn.test.App();
      Code:
       0:   aload_0
       1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
       4:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   new     #16; //class org/imzhs/learn/test/App$A
       3:   dup
       4:   invokespecial   #18; //Method org/imzhs/learn/test/App$A."<init>":()V
       7:   astore_1
       8:   aload_1
       9:   invokevirtual   #19; //Method org/imzhs/learn/test/App$A.hi:()V
       12:  new     #22; //class org/imzhs/learn/test/App$B
       15:  dup
       16:  invokespecial   #24; //Method org/imzhs/learn/test/App$B."<init>":()V
       19:  astore_2
       20:  aload_2
       21:  invokevirtual   #25; //Method org/imzhs/learn/test/App$B.hi:()V
       24:  return}并没有任何变化。
    ======
    总而言之,implements 是向下继承的,所以基类会默认实现父类的所有接口,基类加不加implements对实际的代码逻辑是没有影响的。
      

  3.   

    接口除了有规定要实现哪些方法之外,一个很重要的作用就是起标识作用。
    你可以看一下RandomAccess接口,里面一个方法都没有,它的作用就是标识类的某些功能或者某些特性,你可以理解为注释。
    接口最本质的作用就是告诉程序员这个类可以干什么,这样一来,虽然没见过这个类,但通过接口就可以对这个类有一个本质的认识。
    至于为什么要在子类里重复实现接口。试问,如果某个类上面有10层的继承,若只在第一层声明个接口,那不让人找疯了?