JavaOOP继承
一.繼承的概念
繼承是java面向對象編程技術的一塊基石,因為它允許創建分等級層次的類。
繼承就是子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
eg:
兔子和羊屬于食草動物類,獅子和豹屬于食肉動物類。
食草動物和食肉動物又是屬于動物類。
所以繼承需要符合的關系是:is-a,父類更通用,子類更具體。
雖然食草動物和食肉動物都是屬于動物,但是兩者的屬性和行為上有差別,所以子類會具有父類的一般特性也會具有自身的特性。
類的繼承語法
在 Java 中通過 extends 關鍵字可以申明一個類是從另外一個類繼承而來的,一般形式如下:
class 父類 {
}
class 子類 extends 父類 {
}
eg:
//動物父類 public class Animal { private String name; private int id; public Animal(String myName, int myid) { name = myName; id = myid;} public void eat(){ System.out.println(name+"正在吃"); }public void sleep(){System.out.println(name+"正在睡");}public void introduction() { System.out.println("大家好!我是" + id + "號" + name + "."); } }這個Animal類就可以作為一個父類,然后其他動物類繼承這個類之后,就具有父類當中的屬性和方法,子類就不會存在重復的代碼,維護性也提高,代碼也更加簡潔,提高代碼的復用性(復用性主要是可以多次使用,不用再多次寫同樣的代碼) 繼承之后的代碼:
//企鵝類 public class Penguin extends Animal { public Penguin(String myName, int myid) { super(myName, myid); } } //老鼠類 public class Mouse extends Animal { public Mouse(String myName, int myid) { super(myName, myid); } }繼承的特性:
-
子類擁有父類非private的屬性,方法。
-
子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展。
-
子類可以用自己的方式實現父類的方法。
-
Java的繼承是單繼承,但是可以多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如A類繼承B類,B類繼承C類,所以按照關系就是C類是B類的父類,B類是A類的父類,這是java繼承區別于C++繼承的一個特性。
-
提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯系)。
繼承關鍵字
繼承可以使用 extends 和 implements 這兩個關鍵字來實現繼承,而且所有的類都是繼承于 java.lang.Object,當一個類沒有繼承的兩個關鍵字,則默認繼承object(這個類在?java.lang?包中,所以不需要?import)祖先類。
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關鍵字來實現對父類成員的訪問,用來引用當前對象的父類,類似于C#中我們學過的base關鍵字。
this關鍵字:指向自己的引用,本類中的成員屬性。
class Animal {void eat() {System.out.println("animal : eat");} }class Dog extends Animal {void eat() {System.out.println("dog : eat");}void eatTest() {this.eat(); // this 調用自己的方法super.eat(); // super 調用父類方法 } }public class Test {public static void main(String[] args) {Animal a = new Animal();a.eat();Dog d = new Dog();d.eatTest();} }輸出結果:
animal : eat dog : eat animal : eatfinal關鍵字
final 關鍵字聲明類可以把類定義為不能繼承的,即最終類;或者用于修飾方法,該方法不能被子類重寫:
-
聲明類:
final class 類名 {//類體} -
聲明方法:
修飾符(public/private/default/protected) final 返回值類型 方法名(){//方法體} - Java提供的很多類都是final類(最終類,不能被繼承的類),如String類,Math類,它們不能再有子類。Object類中的一些方法,如getClass( ).notify( ),wait( )都是final方法,只能被子類繼承,而不能被重寫,,但是hashCode(),toString(),equals(Object obj)不是final方法,可以被重寫。
注:實例變量也可以被定義為 final,被定義為 final 的變量不能被修改。被聲明為 final 類的方法自動地聲明為 final,但是實例變量并不是 final,并不會自動聲明,final類中并不都是常量。
abstract關鍵字
? ? abstract和final是功能相反的兩個關鍵字,對比記憶
-
abstract可以用來修飾類和方法,稱為抽象類和抽象方法,不能用來修飾屬性和構造方法。final可以用來修飾類,方法和屬性,不能修飾構造方法。
- abstract不能和private,static同時修飾一個方法,因為抽象方法必然是要在子類中重寫的,私有的如何重寫,一個沒有實現的抽象方法不能用static修飾。不能和final同時修飾一個方法或類,抽象類是要被子類繼承并重寫父類抽象方法的,同理,抽象類只有讓子類繼承才能實例化的,兩者是相矛盾的。但是和public關鍵字不沖突。
Java中的訪問修飾符的總結:
構造器
子類不能繼承父類的構造器(構造方法或者構造函數),但是父類的構造器帶有參數的,則必須在子類的構造器中顯式地通過super關鍵字調用父類的構造器并配以適當的參數列表。類似于c#中的base關鍵字,但是寫法與調用有不同。
如果父類有無參構造器,則在子類的構造器中用super調用父類構造器不是必須的,如果沒有使用super關鍵字,系統會自動調用父類的無參構造器。
eg:class SuperClass {private int n;SuperClass(){System.out.println("SuperClass()");}SuperClass(int n) {System.out.println("SuperClass(int n)");this.n = n;} } class SubClass extends SuperClass{private int n;SubClass(){super(300);System.out.println("SubClass");} public SubClass(int n){System.out.println("SubClass(int n):"+n);this.n = n;} } public class TestSuperSub{public static void main (String args[]){SubClass sc = new SubClass();SubClass sc2 = new SubClass(200); } }
輸出結果:
SuperClass(int n) SubClass SuperClass() SubClass(int n):200Java 重寫(Override)與重載(Overload)
重寫(Override)
重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫, 返回值和形參都不能改變。(即外殼不變,核心重寫!)
重寫的好處在于子類可以根據需要,定義特定于自己的行為。 也就是說子類能夠根據需要實現父類的方法。
重寫方法不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的異常。例如: 父類的一個方法申明了一個檢查異常 IOException,但是在重寫這個方法的時候不能拋出 Exception 異常,因為 Exception 是 IOException 的父類,只能拋出 IOException 的子類異常。
eg:
class Animal{public void move(){System.out.println("動物可以移動");} }class Dog extends Animal{public void move(){System.out.println("狗可以跑和走");} }public class TestDog{public static void main(String args[]){Animal a = new Animal(); // Animal 對象Animal b = new Dog(); // Dog 對象 a.move();// 執行 Animal 類的方法 b.move();//執行 Dog 類的方法 } }方法的重寫規則
- 參數列表必須完全與被重寫方法的相同;
- 返回類型必須完全與被重寫方法的返回類型相同;
- 訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類的一個方法被聲明為public,那么在子類中重寫該方法就不能聲明為protected。
- 父類的成員方法只能被它的子類重寫。
- 聲明為final的方法不能被重寫。
- 聲明為static的方法不能被重寫,但是能夠被再次聲明。
- 子類和父類在同一個包中,那么子類可以重寫父類所有方法,除了聲明為private和final的方法。
- 子類和父類不在同一個包中,那么子類只能夠重寫父類的聲明為public和protected的非final方法。
- 重寫的方法能夠拋出任何非強制異常,無論被重寫的方法是否拋出異常。但是,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明的更廣泛的強制性異常,反之則可以。
- 構造方法不能被重寫。
- 如果不能繼承一個方法,則不能重寫這個方法。
Super關鍵字的使用
當需要在子類中調用父類的被重寫方法時,要使用super關鍵字。
class Animal{public void move(){System.out.println("動物可以移動");} }class Dog extends Animal{public void move(){super.move(); // 應用super類的方法System.out.println("狗可以跑和走");} }public class TestDog{public static void main(String args[]){Animal b = new Dog(); // Dog 對象b.move(); //執行 Dog類的方法 } }重載(Overload)
重載(overloading) 是在一個類里面,方法名字相同,而參數不同。返回類型可以相同也可以不同。
每個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。
最常用的地方就是構造器的重載。
重載規則:
- 被重載的方法必須改變參數列表(參數個數或類型不一樣);
- 被重載的方法可以改變返回類型;
- 被重載的方法可以改變訪問修飾符;
- 被重載的方法可以聲明新的或更廣的檢查異常;
- 方法能夠在同一個類中或者在一個子類中被重載。
- 無法以返回值類型作為重載函數的區分標準。
?
public class Overloading {public int test(){System.out.println("test1");return 1;}public void test(int a){System.out.println("test2");} //以下兩個參數類型順序不同public String test(int a,String s){System.out.println("test3");return "returntest3";} public String test(String s,int a){System.out.println("test4");return "returntest4";} public static void main(String[] args){Overloading o = new Overloading();System.out.println(o.test());o.test(1);System.out.println(o.test(1,"test3"));System.out.println(o.test("test4",1));} }重寫與重載之間的區別
| 參數列表 | 必須修改 | 一定不能修改 |
| 返回類型 | 可以修改 | 一定不能修改 |
| 異常 | 可以修改 | 可以減少或刪除,一定不能拋出新的或者更廣的異常 |
| 訪問 | 可以修改 | 一定不能做更嚴格的限制(可以降低限制) |
總結
方法的重寫(Overriding)和重載(Overloading)是java多態性的不同表現,重寫是父類與子類之間多態性的一種表現,重載可以理解成多態的具體表現形式。
- (1)方法重載是一個類中定義了多個方法名相同,而他們的參數的數量不同或數量相同而類型和次序不同,則稱為方法的重載(Overloading)。
- (2)方法重寫是在子類存在方法與父類的方法的名字相同,而且參數的個數與類型一樣,返回值也一樣的方法,就稱為重寫(Overriding)。
- (3)方法重載是一個類的多態性表現,而方法重寫是子類與父類的一種多態性表現。
抽象類和抽象方法
在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。
抽象類除了不能實例化對象之外,類的其它功能依然存在,成員變量、成員方法和構造方法的訪問方式和普通類一樣。
由于抽象類不能實例化對象,所以抽象類必須被繼承,才能被使用。也是因為這個原因,通常在設計階段決定要不要設計抽象類。
父類包含了子類集合的常見的方法,但是由于父類本身是抽象的,所以不能使用這些方法。
在Java中抽象類表示的是一種繼承關系,一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
在Java語言中使用abstract class來定義抽象類。
/* 文件名 : Employee.java */ public abstract class Employee {private String name;private String address;private int number;public Employee(String name, String address, int number){System.out.println("Constructing an Employee");this.name = name;this.address = address;this.number = number;}public double computePay(){System.out.println("Inside Employee computePay");return 0.0;}public void mailCheck(){System.out.println("Mailing a check to " + this.name+ " " + this.address);}public String toString(){return name + " " + address + " " + number;}public String getName(){return name;}public String getAddress(){return address;}public void setAddress(String newAddress){address = newAddress;}public int getNumber(){return number;} }我們不能實例化一個Employee類的對象,但是如果我們實例化一個Salary類對象,該對象將從 Employee 類繼承7個成員方法,且通過該方法可以設置或獲取三個成員變量。
/* 文件名 : AbstractDemo.java */ public class AbstractDemo {public static void main(String [] args){Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);System.out.println("Call mailCheck using Salary reference --");s.mailCheck();System.out.println("\n Call mailCheck using Employee reference--");e.mailCheck();} }抽象方法
如果你想設計這樣一個類,該類包含一個特別的成員方法,該方法的具體實現由它的子類確定,那么你可以在父類中聲明該方法為抽象方法。
Abstract關鍵字同樣可以用來聲明抽象方法,抽象方法只包含一個方法名,而沒有方法體。
抽象方法沒有定義,方法名后面直接跟一個分號,而不是花括號。
public abstract class Employee {private String name;private String address;private int number;public abstract double computePay();//其余代碼 }聲明抽象方法會造成以下兩個結果:
- 如果一個類包含抽象方法,那么該類必須是抽象類。
- 任何子類必須重寫父類的抽象方法,或者聲明自身為抽象類。
繼承抽象方法的子類必須重寫該方法。否則,該子類也必須聲明為抽象類。最終,必須有子類實現該抽象方法,否則,從最初的父類到最終的子類都不能用來實例化對象。
如果Salary類繼承了Employee類,那么它必須實現computePay()方法:
/* 文件名 : Salary.java */ public class Salary extends Employee {private double salary; // Annual salarypublic double computePay(){System.out.println("Computing salary pay for " + getName());return salary/52;}//其余代碼 }抽象類總結
-
1. 抽象類不能被實例化(初學者很容易犯的錯),如果被實例化,就會報錯,編譯無法通過。只有抽象類的非抽象子類可以創建對象。
-
2. 抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
-
3. 抽象類中的抽象方法只是聲明,不包含方法體,就是不給出方法的具體實現也就是方法的具體功能。
-
4. 構造方法,類方法(用static修飾的方法)不能聲明為抽象方法。
-
5. 抽象類的子類必須給出抽象類中的抽象方法的具體實現,除非該子類也是抽象類。
轉載于:https://www.cnblogs.com/java-123/p/8973562.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: php 安装xdebug扩展
- 下一篇: Java数组的十大方法