繼承是從已有的類別中衍生出新的類,新的類別能吸收已有類別的資料屬性和行為,並能擴充新的能力。繼承即常說的is-a關係。子類別繼承父類別的特徵和行為,使得子類別具有父類別的各種屬性和方法。或子類別從父類別繼承方法,使得子類別具有父類別相同的行為。
範例:
例如可以先定義一個類別叫車,車有以下屬性:車體大小,顏色,方向盤,輪胎,而又由車這個類派生出轎車和卡車兩個類,為轎車添加一個小後備箱,而為卡車添加一個大貨箱。
繼承所表達的就是一種物件類別之間的相交關係,它使得某類別物件可以繼承另外一類別物件的資料成員和成員方法。若類別B繼承類A,則屬於B的物件便具有類別A的全部或部分性質(資料屬性)和功能(操作),我們稱被繼承的類別A為基底類別、父類別或超類,而稱繼承類別B為A的衍生類別或子類別。
表示父類別和子類別的術語:父類別和子類別、超類別和子類別、基底類別和衍生類,他們表示的是同一個意思。
開發動物類,其中動物分別為企鵝以及老鼠,要求如下:
企鵝:屬性(姓名,id),方法(吃,睡,自我介紹)
老鼠:屬性(姓名,id),方法(吃,睡,自我介紹)
企鵝和老鼠都是動物我們是不是可以寫一個動物類,這樣代碼是不是簡潔了許多。有的人說我就想單獨建兩個類寫這個屬性,我只能告訴你可以,但這好比,你父親給你了幾百萬,你偏不要,把這些錢扔了非要自己去掙,你想這樣我也沒辦法。既然java給我們提供了繼承我們就要好好用這樣會大大提高我們的開發效率,比如:維護性提高了,程式碼也更加簡潔,提高程式碼的複用性也提高了(復用性指可以多次使用,不用再寫一次同樣的程式碼)。
1、繼承可以減少重複的程式碼。例如父類別已經提供的方法,子類別可以直接使用,不必再去實作。
2、繼承是多態性的前提。當然使用繼承的同時也提高了類別的耦合度。
當你不需要父類別的屬性時,可以覆寫調原屬性。
繼承分為單一繼承和多重繼承。單繼承是指一個子類別最多只能有一個父類別。多重繼承是一個子類別可以有二個以上的父類別。由於多重繼承會帶來二義性,在實際應用上應盡量使用單一繼承。 Java語言中的類別只支援單繼承,而介面支援多重繼承。 Java中多重繼承的功能是透過介面(interface)來間接實作的。
繼承可以使用extends 和implements 這兩個關鍵字來實現繼承,而且所有的類別都是繼承於java.lang.Object,當一個類別沒有繼承的兩個關鍵字,則預設繼承object(這個類別在java.lang 套件中,所以不需要import)祖先類別。
父類別—>父類別的初始化物件中的屬性—>父類別的建構方法—>子類別—>子類別的初始化物件中的屬性—>子類別的建構方法
若有建構方法:則先執行屬性,再執行建構方法
若建構方法中沒有對name屬性進行賦值,則name的值為類別屬性所賦的值
在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 關鍵字可以變相的使java具有多繼承的特性,使用範圍為類別繼承接口的情況,可以同時繼承多個接口(接口跟接口之間採用逗號分隔)。
public interface A { public void eat(); public void sleep(); } public interface B { public void show(); } public class C implements A,B { }
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中文網其他相關文章!