zoukankan      html  css  js  c++  java
  • Java中类继承、接口实现的一些要注意的细节问题

    1.接口A和接口B有相同的方法,只是返回值不同,则实现类不能同时实现这两个接口中的方法。

    接口A有void C()方法,接口B有int C()方法,则无法同时实现这两个接口。

    Java为了弥补类单继承的不足,引入了类多实现接口的机制,不过多实现某个接口也是有一定限制的,比如:

    public interface A
    {
        void C();
    }
    public interface B
    {
        int C();
    }

    那么同时实现这两个接口是不可能的:

    这个错误是无法被修复的。试想,类AB实现接口A和接口B,那么接口A里面的抽象方法和接口B里面的抽象方法参数列表都相同仅有返回值不同,类AB应该实现哪个呢?实现接口A的"void C()",那么接口B的"int C()"怎么办?实现接口B的"int C()"那么接口A的"void C()"怎么办?因为"void C()"、"int C()"属于方法参数相同,返回值不同,这两个方法是不可以重载的,所以同时实现两个方法也不可能。因此,在这里Java只能报错了。

    2.A是接口,B实现A,C继承B,则C也是A的子类

    有一个接口A,B实现了A接口,C继承自B类,则C也是A的子类,看一下:

    public interface A
    {
    
    }
    public class B implements A
    {
    
    }
    public class C extends B
    {
    
    }
    public static void main(String[] args)
    {
        C c = new C();
        System.out.println(c instanceof A);
    }

    返回结果是true。这是一个不难理解的结论,想到求证这个结论是因为有一次在研究LinkedHashMap的时候:

    public class LinkedHashMap<K,V>
        extends HashMap<K,V>
        implements Map<K,V>

    既然LinkedHashMap已经继承了HashMap了,HashMap是Map的实现类,那为什么LinkedHashMap还要实现Map呢,岂不是多此一举吗?由此想到了会不会是因为继承了HashMap不代表LinkedHashMap是Map的子类所以LinkedHashMap要专门再实现一下Map,做了上面的实验,发现是我多虑了,可能Sun的开发人员就想这么写吧,呵呵。

     3.父子类有同名变量和同名方法的处理.

    子类不会覆盖父类的同名变量。

    class Base {
        int count = 2;
    
        public void display() {
            System.out.println("Base : " + this.count);
        }
    }
    
    class Derived extends Base {
        int count = 20;
    
        @Override
        public void display() {
            System.out.println("Derived : " + this.count);
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Base bd = new Derived();
            System.out.println(bd.count);
            bd.display();
            Derived d = new Derived();
            Base d2b = d;
            System.out.println(d2b.count);
        }
    }
    

     运行结果为:

    2
    Derived : 20
    2
    

      

    原因如下: 

    编译器有一条这样的规定:编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。


    编译器在处理方法和成员变量时存在区别。在子类没有重写父类的方法时,编译器会将父类中的方法copy到子类中,如果子类复写,则无法copy。对于实例变量而言却不存在这样的现象,子类定义的同名变量无法覆盖父类的同名变量,就如同上面“2和20”的例子,两个都存储了,正是由于变量和方法之间的处理存在这样的区别,所以对于一个引用类型的变量而言:

    • 访问变量时,按照声明该变量时的类型(编译时类型)
    • 访问方法时,按照实际引用的对象的类型(运行时类型)

    因此,对于System.out.println(bd.count);而言,bd的编译时类型为Base,因此就会输出Base的count,也就是2;对于bd.display();而言,调用的是方法,bd的运行时类型为Derived,因此也就会调用了子类的display()方法。System.out.println(d2b.count);同理,会输出编译时类型Base的count了

    4.注意父子类同名不同参数方法

    上面的例子稍微修改一下:

    class Father {
        public void foo(Object o) {
            System.out.println("Father.foo()");
        }
    }
    
    class Son extends Father{
        public void foo(String s) {
            System.out.println("Son.foo()");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Son son = new Son();
            son.foo(new Object());
        }
    }
    

      运行结果:

    Father.foo()
    

      注意这个不是overload(方法重载),虽然方法名称一样,但是方法参数的类型不一样,原则上也属于两个方法,曾经看到有人将上面也归属于方法重写,个人表示有点异议。

          不同不同于上面的例子,son从父类中继承到了foo(Object o)方法,son会根据传入的参数不同而决定使用哪个方法。对于本例,传入的是Object,因此son会使用继承的foo方法,而非自己的。

     5.一个抽象类继承接口,可以不实现接口的方法。

    一个实现类继承自一个抽象类并且实现了多个接口,那么必须实现所有未被实现的抽象方法

    举个例子:
    
    public interface InterfaceA
    {
        void A1();
        void A2();
    }
    public interface InterfaceB
    {
        void B1();
        void B2();
    }
    
    public abstract class AbstractC implements InterfaceA, InterfaceB
    {
        public void A1(){} // 我实现了InterfaceA的A1()方法
        public void B2(){} // 我实现了InterfaceB的B2()方法
        
        abstract void C(); // 我自己定义了一个抽象方法
    }

    那么要定义一个ClassD继承自AbstractC,则必须:

    public class ClassD extends AbstractC{
       public void A2(){} // 我必须实现InterfaceA中未被实现的A2()方法
    
       public void B1(){} // 我必须实现InterfaceB中未被实现的B1()方法
    
       void C(){} // 我必须实现AbstractC中未被实现的C()方法
    }
    

      

  • 相关阅读:
    查看git submodule更改
    /var/lib/docker空间占用过大迁移
    docker -修改容器
    docker重命名镜像repository和tag
    方法的重写、重载。
    方法的声明与使用。
    二维数组。
    标准输入输出流概述和输出语句。
    冒泡排序法。
    IO流,对象操作流优化。
  • 原文地址:https://www.cnblogs.com/haitaofeiyang/p/7721991.html
Copyright © 2011-2022 走看看