首頁  >  文章  >  Java  >  Java物件導向之關於繼承的範例詳解

Java物件導向之關於繼承的範例詳解

黄舟
黄舟原創
2017-09-06 10:12:301678瀏覽

繼承

介紹

  繼承是從已有的類別中衍生出新的類,新的類別能吸收已有類別的資料屬性和行為,並能擴充新的能力。繼承即常說的is-a關係。子類別繼承父類別的特徵和行為,使得子類別具有父類別的各種屬性和方法。或子類別從父類別繼承方法,使得子類別具有父類別相同的行為。

 範例:
  例如可以先定義一個類別叫車,車有以下屬性:車體大小,顏色,方向盤,輪胎,而又由車這個類派生出轎車和卡車兩個類,為轎車添加一個小後備箱,而為卡車添加一個大貨箱。

 繼承所表達的就是一種物件類別之間的相交關係,它使得某類別物件可以繼承另外一類別物件的資料成員和成員方法。若類別B繼承類A,則屬於B的物件便具有類別A的全部或部分性質(資料屬性)和功能(操作),我們稱被繼承的類別A為基底類別、父類別或超類,而稱繼承類別B為A的衍生類別或子類別。

 表示父類別和子類別的術語:父類別和子類別、超類別和子類別、基底類別和衍生類,他們表示的是同一個意思。

為什麼需要繼承

  開發動物類,其中動物分別為企鵝以及老鼠,要求如下:
  企鵝:屬性(姓名,id),方法(吃,睡,自我介紹)
  老鼠:屬性(姓名,id),方法(吃,睡,自我介紹)
企鵝和老鼠都是動物我們是不是可以寫一個動物類,這樣代碼是不是簡潔了許多。有的人說我就想單獨建兩個類寫這個屬性,我只能告訴你可以,但這好比,你父親給你了幾百萬,你偏不要,把這些錢扔了非要自己去掙,你想這樣我也沒辦法。既然java給我們提供了繼承我們就要好好用這樣會大大提高我們的開發效率,比如:維護性提高了,程式碼也更加簡潔,提高程式碼的複用性也提高了(復用性指可以多次使用,不用再寫一次同樣的程式碼)。

 作用:

  1、繼承可以減少重複的程式碼。例如父類別已經提供的方法,子類別可以直接使用,不必再去實作。

  2、繼承是多態性的前提。當然使用繼承的同時也提高了類別的耦合度。

  當你不需要父類別的屬性時,可以覆寫調原屬性。

Java繼承分類

  繼承分為單一繼承和多重繼承。單繼承是指一個子類別最多只能有一個父類別。多重繼承是一個子類別可以有二個以上的父類別。由於多重繼承會帶來二義性,在實際應用上應盡量使用單一繼承。 Java語言中的類別只支援單繼承,而介面支援多重繼承。 Java中多重繼承的功能是透過介面(interface)來間接實作的

繼承實作

  繼承可以使用extends 和implements 這兩個關鍵字來實現繼承,而且所有的類別都是繼承於java.lang.Object,當一個類別沒有繼承的兩個關鍵字,則預設繼承object(這個類別在java.lang 套件中,所以不需要import)祖先類別。

繼承的初始化順序:

  父類別—>父類別的初始化物件中的屬性—>父類別的建構方法—>子類別—>子類別的初始化物件中的屬性—>子類別的建構方法

  若有建構方法:則先執行屬性,再執行建構方法

  若建構方法中沒有對name屬性進行賦值,則name的值為類別屬性所賦的值

extends關鍵字

在Java 中,類別的繼承是單一繼承,也就是說,一個子類別只能擁有一個父類,所以extends 只能繼承一個類別。

/*动物类*/
public class Animal { 
    private String name;   
    private int id; 
    public Animal(String myName, String myid) { 
        //初始化属性值
    } 
    public void eat() {  //吃东西方法的具体实现  } 
    public void sleep() { //睡觉方法的具体实现  } 
} 
 
/*企鹅是动物,所以可以继承动物类*/
public class Penguin  extends  Animal{ 
//企鹅继承了动物类,所以拥有了动物类的属性和方法
}

implements關鍵字

  使用implements 關鍵字可以變相的使java具有多繼承的特性,使用範圍為類別繼承接口的情況,可以同時繼承多個接口(接口跟接口之間採用逗號分隔)。

public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}

super 與this 關鍵字

super關鍵字:我們可以透過super關鍵字來實現對父類別成員的訪問,用來引用目前物件的父類。

 註:
  1.只能在建構方法或實例方法內使用super關鍵字,而在靜態方法和靜態程式碼區塊內不能使用super關鍵字

  2.如果父類別中的成員變數和方法被定義為private類型,那麼子類別永遠無法存取它們,如果試圖採用super.var的形式去存取父類別的private類型的var變量,就會導致編譯錯誤

this關鍵字:指向自己的引用,表示目前正在呼叫此方法的物件參考。

 註:
  1.當具多個重載的構造器時,且一個構造器需要調用另外一個構造其,在其第一行使用this(param)形式調用,且只能在第一行;

  2.當物件中一個方法需要呼叫本物件中其他方法時,使用this作為主調,也可以不寫,實際上預設就是this作為主調;

  3.当对象属性和方法中的局部变量名称相同时,在该方法中需要显式的使用this作为主调,以表示对象的属性,若不存在此问题,可以不显式的写this。

  其实,其牵涉到的一个问题就是变量的查找规则先局部变量 => 当前类中定义的变量 => 其父类中定义的可以被子类继承的变量 => 父类...

这块要完全理解需要看上面我写的“继承的初始化顺序”从这里可以看到程序是如何初始化的。

/**
 * 父类
 * @author gacl
 *
 */
class FatherClass {
    public int value;
    public void f() {
        value=100;
        System.out.println("父类的value属性值="+value);
    }
}

/**
 * 子类ChildClass从父类FatherClass继承
 */
class ChildClass extends FatherClass {
    /**
     * 子类除了继承父类所具有的valu属性外,自己又另外声明了一个value属性,
     * 也就是说,此时的子类拥有两个value属性。
     */
    public int value;
    /**
     * 在子类ChildClass里面重写了从父类继承下来的f()方法里面的实现,即重写了f()方法的方法体。
     */
    public void f() {
        super.f();//使用super作为父类对象的引用对象来调用父类对象里面的f()方法
        value=200;//这个value是子类自己定义的那个valu,不是从父类继承下来的那个value
        System.out.println("子类的value属性值="+value);
        System.out.println(value);//打印出来的是子类自定义的那个value的值,这个值是200
        /**
         * 打印出来的是父类里面的value值,由于子类在重写从父类继承下来的f()方法时,
         * 第一句话“super.f();”是让父类对象的引用对象调用父类对象的f()方法,
         * 即相当于是这个父类对象自己调用f()方法去改变自己的value属性的值,由0变了100。
         * 所以这里打印出来的value值是100。
         */
        System.out.println(super.value);
    }
}

/**
 * 测试类
 */
public class TestInherit {
    public static void main(String[] args) {
        ChildClass cc = new ChildClass();
        cc.f();
    }
}

运行结果:
  父类的value属性值=100
  子类的value属性值=200
  200
  100

分析:
  执行   ChlidClass cc = new ChlidClass();

 首先在栈空间里面会产生一个变量cc,cc里面的值是什么这不好说,总而言之,通过这个值我们可以找到new出来的ChlidClass对象。由于子类ChlidClass是从父类FatherClass继承下来的,所以当我们new一个子类对象的时候,这个子类对象里面会包含有一个父类对象,而这个父类对象拥有他自身的属性value。这个value成员变量在FatherClass类里面声明的时候并没有对他进行初始化,所以系统默认给它初始化为0,成员变量(在类里面声明)在声明时可以不给它初始化,编译器会自动给这个成员变量初始化,但局部变量(在方法里面声明)在声明时一定要给它初始化,因为编译器不会自动给局部变量初始化,任何变量在使用之前必须对它进行初始化。

  子类在继承父类value属性的同时,自己也单独定义了一个value属性,所以当我们new出一个子类对象的时候,这个对象会有两个value属性,一个是从父类继承下来的value,另一个是自己的value。在子类里定义的成员变量value在声明时也没有给它初始化,所以编译器默认给它初始化为0。即(父类的value为0,子类的value为0;

  执行第二句话:   cc.f();

 当new一个对象出来的时候,这个对象会产生一个this的引用,这个this引用指向对象自身。如果new出来的对象是一个子类对象的话,那么这个子类对象里面还会有一个super引用,这个super指向当前对象里面的父对象。所以相当于程序里面有一个this,this指向对象自己,还有一个super,super指向当前对象里面的父对象。

  这里调用重写之后的f()方法,方法体内的第一句话:“super.f();”是让这个子类对象里面的父对象自己调用自己的f()方法去改变自己value属性的值,父对象通过指向他的引用super来调用自己的f()方法,所以执行完这一句以后,父对象里面的value的值变成了100。接着执行“value=200;”这里的vaule是子类对象自己声明的value,不是从父类继承下来的那个value。所以这句话执行完毕后,子类对象自己本身的value值变成了200。

以上是Java物件導向之關於繼承的範例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn