关于继承与多态

2019-12-19 16:04:54来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

关于继承与多态

 关于继承与多态的几点总结

1、父类的所有方法都能被继承吗?能被重写吗?能表现出多态性吗?

1.1 非静态方法

  1.1.1 被public、default、protected修饰的非静态方法

  能被子类继承,如果没有被final修饰,则能被重写,当父类引用指向子类对象时,表现出多态性。

  1.1.2 被private修饰的非静态方法

  不能被子类继承,更不能被重写,没有多态性(有的人理解为父类的所有包括私有的成员都能被继承,只是在子类中不可见,我更倾向于前者)。当子类中出现与父类私有方法名和参数相同的时候会发生什么呢?

class Parent{
    private void f() {
        System.out.println("parent");
    }
    public static void main(String[] args) {
        Parent p = new Child();   
        p.f();
    }
}
class Child extends Parent{
    public void f() {         //父类的私有方法在子类中不可见,子类的f()方法是一个全新的方法,编译器认为f()方法没有被重写
    System.out.println("child"); 
  }
}

打印结果:

parent

1.2 静态方法

  静态方法可以被继承,不能被重写,也就不能表现出多态性

class Parent{
    public static void f() {
        System.out.println("parent");
    }
}
class Child extends Parent{
    public static void f() {
        System.out.println("child");
    }
    public static void main(String[] args) {
        Parent p = new Child();   //静态方法能被继承,但不能被重写
        p.f();
        Child c = new Child();
        c.f();
    }
}

打印结果:

parent
child

 1.3 构造方法

  构造方法不能被继承,不能被重写,没有多态性。

  构造方法既不是静态方法也不是非静态方法,构造方法中会有一个this对象作为参数传进去,所以我们可以在构造方法内部对对象属性进行初始化,也可以在构造方法内调用非静态方法。

  如果该非静态方法被重写过,那么构造器内部会不会存在多态行为呢?参考Java编程思想中的一个例子:

class Glyph {
    void draw() {
        System.out.println("Glyph.draw()");
    }

    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
}

class RoundGlyph extends Glyph {
    private int radius = 1;
    RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGLyph(), radius = " + radius);
    }
    void draw() {
        System.out.println("RoundGlyph.draw(), radius = " + radius);
    }
}

class RolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}

 

  在父类构造器中调用被子类重写的非静态方法,会发生多态行为,但这并不是我们想要的结果,原因如下:

  1. 在其他任何事物发生之前,将分配给对象的存储空间初始化为二进制的零;
  2. 如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用),由于步骤1的缘故,我们此时会发现radius的值为0;
  3. 按照声明的顺序调用成员的初始化方法;
  4. 调用导出类的构造器主体。

  因此,在编写构造器中有一条有效的准则:“用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其他方法”。在构造器中,唯一能够安全调用的是基类中的final方法(包括private方法),因为这些方法不能被子类覆盖,也就不会出现上述的问题。

2、父类的所有属性都能被继承吗?能被重写吗?能表现出多态性吗?

2.1 被public,default,protected修饰的属性

  都能被继承(与是否是静态的无关),不能被重写,没有多态性。当子类中定义了与父类相同的属性时,子类会在不同的存储空间同时保留自己的和父类的属性

class Child extends Parent {
    public static int a = 2;
    public void getA() {
        System.out.println("a = "+a);
    }
    public void ParentA() {
        System.out.println("super.a = " + super.a);
    }
    public static void main(String[] args) {
        Parent p = new Child();
        System.out.println(p.a);  //任何域访问操作都由编译器解析
        Child c = new Child();
        c.getA();     //直接访问field默认会获取自己的域
        c.ParentA();  //通过super.field能获取父类的域
    }
}

2.1 被private修饰的属性

  个人理解为可以被继承,但是不能直接访问,能通过父类public、default、或protected方法间接访问(也有人理解为不能为继承)

class Parent {
    private int a;
    public Parent(int a) {
        this.a = a;
    }
    public int getA() {
        return a;
    }
}

class Child extends Parent {
    public Child(int a) {
        super(a);
    }
    public static void main(String[] args) {
        Child c = new Child(1);    
        System.out.println(c.getA());  //结果为1
    }
}

   当父类和子类存在相同私有属性时:

class Parent {
    private int a;
    public Parent(int a) {
        this.a = a;
    }
    public int getA() {
        return a;
    }
}

class Child extends Parent {
    private int a = 2;
    public Child(int a) {
        super(a);
    }
    public static void main(String[] args) {
        Child c = new Child(1);    
        System.out.println(c.getA());  //1
        System.out.println(c.a);       //2
    }
}

   关于继承与多态以及对象初始化过程还有很多不是很理解的地方,先记录下来,等日后有时间研究一下java虚拟机的原理再来完善!


原文链接:https://www.cnblogs.com/xiaohang123/p/12070385.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:线程安全的无锁RingBuffer的实现

下一篇:sleep方法要求处理中断异常:InterruptedException