• Java继承


    继承介绍

    在java语言中,类可以从其他类继承而来,并继承父类的成员和方法。

    继承是简单但是非常强大:当你需要创建一个新类,但是已经有其他类,它已经包含了一些你需要的代码,那么你可以从已有的这个类,继承新的类。这样,你不用写重复的代码和调试,就可以重用已有类的成员和方法。

    子类从父类继承所有的成员(变量,方法和内部类),构造方法不是成员,所以不会被继承,但是子类的构造方法可以调用父类的构造方法。

    在java平台中,java.lang.Object是所有类的父类,有些类直接继承Object,有些类间继承其他类,其他类继承自Object。

    继承例子

    Bicycle类

    复制代码
    public class Bicycle {

    // the Bicycle class has
    // three fields
    public int cadence;
    public int gear;
    public int speed;

    // the Bicycle class has
    // one constructor
    public Bicycle(int startCadence, int startSpeed, int startGear) {
    gear
    = startGear;
    cadence
    = startCadence;
    speed
    = startSpeed;
    }

    // the Bicycle class has
    // four methods
    public void setCadence(int newValue) {
    cadence
    = newValue;
    }

    public void setGear(int newValue) {
    gear
    = newValue;
    }

    public void applyBrake(int decrement) {
    speed
    -= decrement;
    }

    public void speedUp(int increment) {
    speed
    += increment;
    }

    }
    复制代码

    一个类MountainBike类继承自Bicycle:

    复制代码
    public class MountainBike extends Bicycle {

    // the MountainBike subclass adds
    // one field
    public int seatHeight;

    // the MountainBike subclass has one
    // constructor
    public MountainBike(int startHeight,
    int startCadence,
    int startSpeed,
    int startGear) {
    super(startCadence, startSpeed, startGear);
    seatHeight
    = startHeight;
    }

    // the MountainBike subclass adds
    // one method
    public void setHeight(int newValue) {
    seatHeight
    = newValue;
    }
    }
    复制代码

    MountainBike继承Bicycle的所有变量和方法,并添加了seatHeight变量和对应的set方法。MountainBike新类,它有四个变量和五个方法,不过你未必要全部都要使用。

    如果Bicycle的方法很复杂,并已经使用了大量的时间调试,那么这种复用代码的方式,是相当简单并有价值。

     

    子类能做的事情

    子类继承父类所有的public和protected成员,不管父类在哪个包。如果子类和父类在同一个包,它也会继承父类的 package-private成员(没有修饰public,privat,protected的成员),对于继承的成员,可以替换它,隐藏它,或者补充 新成员:

    1.被继承的成员变量可以直接使用,就像使用其他成员

    2.声明一个新成员变量,名字和父类的成员变量名字一样,就隐藏了该成员(不推荐)

    3.声明不存在父类的新成员变量。

    4.继承的方法可以直接使用

    5.在子类实现一个与父类签名一样的方法,可以覆盖父类的方法。

    6.在子类实现一个与父类签名一样的新的static方法,可以覆盖父类的方法。

    7.可以声明一个不存在父类的新成员方法。

    8.实现一个子类的构造器,通过隐式或者显示使用super调用父类的构造器。

    父类的private成员

    子类不会继承父类的private成员,但是,如果父类已经有public或protected方法访问的私有成员,那么通过可以继承的方法,依然可以间接访问父类的private成员.

    内部类可以访问嵌套类的所有成员,包括嵌套类private成员。

    对象转换

    一个对象的实例化,我们可能这么写:

    public MountainBike myBike = new MountainBike();

    这表示myBike是MountainBike类型。

    MountainBike派生自BicycleObject,所以,一个MountainBike实例既是一个Bicycle,也是一个Object.

    而逆转的未必是可以的:一个Bicycle未必是MountainBike。同样的,一个Object未必是Bicycle或者MountainBike。

    类型转换显示在允许的继承和实现中,一个对象,从一种类型替换为另一种类型的用法.例如

    Object obj = new MountainBike();

    这样obj既是一个Object,也是一个Mountainbike。

    另一边,我们这么写:

    MountainBike myBike = obj;

    我们会遇到一个编译时错误,因为对于obj,编译器不知道它是一个MountainBike。尽管如此,我们可以告诉编译器,通过显示转换,将obj转换为类型MountainBike

    MountainBike myBike = (MountainBike)obj;

    这种转换为插入一个运行时检测,编译器会安全假设obj是一个MountainBike类型,但如果obj不是一个MountainBike,运行时,会抛出异常。

    当然,你可以使用instanceof操作符做逻辑测试,判断obj是否MountainBike类型再做转换

    if (obj instanceof MountainBike) {
    MountainBike myBike
    = (MountainBike)obj;
    }

    这样,我们做类型转换,就不会有运行时异常抛出了。

     

    继承中属性、方法和对象的关系

        大家都知道子类继承父类是类型的继承,包括属性和方法!如果子类和父类中的方法签名相同就叫覆盖!如果子类和父类的属性相同,父类就会隐藏自己的属性!

    但是如果我用父类和子类所创建的引用指向子类所创建的对象,父类引用所调用子类对象中的属性值或方法的结果是什么呢?

    看代码:

    复制代码
    public class FieldDemo {  
    public static void main(String[] args){
    Student t
    = new Student("Jack");
    Person p
    = t;//父类创建的引用指向子类所创建的对象
    System.out.println(t.name+","+p.name);
    System.out.println(t.getName()
    +","+p.getName());
    }

    }
    class Person{
    String name;
    int age;
    public String getName(){
    return this.name;
    }
    }
    class Student extends Person{
    String name;
    // 属性和父类属性名相同,但在做开发时一般不会和父类属性名相同!!
    public Student(String name){
    this.name = name;
    super.name = "Rose"; // 为父类中的属性赋值
    }
    public String getName(){
    return this.name;
    }
    }
    复制代码

    返回结果是:Jack,Rose
    Jack,Jack

    原因是:在Java中,属性绑定到类型,方法绑定到对象!

    内存图如下:

    关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序的探讨 .

    综合网上的相关帖子和我自己的调试,研究了一下关于JAVA继承类的静态变量、成员变量、父子类构造方法调用顺序问题。首先看一段程序:

    class X {
        Y b
    =new Y();//7、这里是父类成员变量初始化
        static Y sb=new Y();//1、父类静态变量,输出static Y(静态代码块先初始化),2、Y

       
    static{
            System.out.println(
    "static X父类静态代码块");//3、执行静态代码块
            new Y();//4、这里只是输出Y,有static Y(静态代码块只执行一次)
        }
        X() {

            System.out.println("X");//8、父类成员变量初始化之后,执行父类构造器输出X
        }
    }

    class Y {
       
    static{
            System.out.println(
    "static Y");       
        }
        Y() {
    //执行构造函数
           
    //这里有个super()==Object()
            System.out.println("Y");
        }
    }

    publicclass Z extends X {
       
    finalstaticint mead=45;
       
    finalbyte b=16;
       
    static Y sb=new Y();//5、子类的静态变量,输出Y
        static{      
            System.out.println(
    "static Z");//6、子类的静态代码块
        }
        Y y
    =new Y();//9、这里是子类成员变量初始化

        Z() {
           
    //这里有super()==new X()
            this.y =null;
            System.out.println(
    "Z");//10、子类成员变量初始化之后,执行子类构造器输出Z
        }

       
    publicstaticvoid main(String[] args) {
           
    new Z();

        }
    }

    执行结果:

    static Y
    Y
    static X父类静态代码块
    Y
    Y
    static Z
    Y
    X
    Y
    Z

    解释:
    static的东西在编译的时候就向内存要到了存取空间,他们的初始化要早于非static,顺序是先父类再子类。
    初始化类,先执行super()父类的的构造函数(final和static之后),父类的构造函数先执行super()直到object super(),完了执行一般成员变量的初始化

    一般成员变量初始化完毕,执行构造器里面的代码(super()之后的代码).
    父类的初始化完成后(子类构造器里面super执行完毕),才轮到子类的成员变量初始化
    子类成员变量初始化完毕,开始执行子类构造器里面的代码(super()之后的代码).

    注意:

    静态块和静态变量的调用顺序是按照书写顺序执行的,比如上边X类中静态块和静态变量的书写顺序颠倒如下:

    class X {
      Y b = new Y();
           static{
            System.out.println("static X父类静态代码块");
            new Y();
        }
        static Y sb= new Y();
        X() {
            System.out.println("X");
        }
      
    }

    则执行结果为:

    static X父类静态代码块
    static Y
    Y
    Y
    Y
    static Z
    Y
    X
    Y
    Z

    最后:

    确定变量空间和初始化赋值是分开进行的,先一次性确定静态成员变量空间 并赋给二进制0 ,然后按照书写顺序逐一赋值

    如下代码,输出结果是0.0

    publicclass Test {
       
    staticint i=f();
       
    staticdouble d=0.1234;
       
    publicstaticvoid main(String[] args) {
           
    new Test();
        }
       
    staticint f(){
            System.out.println(d);
           
    return3;
        }
    }

    原址:

    http://blog.csdn.net/pisota/article/details/5332848


  • 相关阅读:
    URAL 1948 H
    int、long、long long取值范围
    Bonetrousle HackerRank 数学 + 思维题
    湖南省第十二届大学生计算机程序设计竞赛 problem A 2016
    Abbreviation ---- hackerrank
    POJ 3321 Apple Tree DFS序 + 树状数组
    HDU
    PICO CTF 2013 PHP 2: 85
    XSS进阶三
    XSS进阶二
  • 原文地址:https://www.cnblogs.com/biggestfish/p/2916817.html
Copyright © 2020-2023  润新知