Java中的繼承、封裝、多態的理解
Java中的繼承、封裝、多態
繼承的理解:
1、繼承是面向對象的三大特征之一,也是實現代碼復用的重要手段。Java的繼承具有單繼承的特點,每個子類只有一個直接父類。
2、Java的繼承通過extends關鍵字來實現,實現繼承的類被稱為子類,被繼承的類稱為父類(有的也稱其為基類、超類),父類和子類的關系,是一種一般和特殊的關系。就像是水果和蘋果的關系,蘋果繼承了水果,蘋果是水果的子類,水果是蘋果的父類,則蘋果是一種特殊的水果。
3、Java使用extends作為繼承的關鍵字,extends關鍵字在英文是擴展的意思,而不是繼承。為什麽國內把extends翻譯成繼承呢?除了與歷史原因有關外,把extends翻譯成為繼承也是有其道理的:子類擴展父類,將可以獲得父類的全部屬性和方法,這與漢語中得繼承(子輩從父輩那裏獲得一筆財富成為繼承)具有很好的類似性。值得指出的是:
4、實例:
class BaseClass{
public double weight;
public void info() {
System.out.println("我的體重是"+weight+"千克");
}
}
public class ExtendsDemo001 extends BaseClass {
public static void main(String[] args) {
//創建ExtendsDemo001對象
ExtendsDemo001 ed = new ExtendsDemo001();
//ExtendsDemo001本身沒有weight屬性,但是ExtendsDemo001的父類有weight屬性,也可以訪問ExtendsDemo001對象的屬性
ed.weight = 56;
//調用ExtendsDemo001對象的info()方法
ed.info();
}
}
打印結果為:我的體重是56.0千克
5、Java類只能有一個父類。這句話是錯誤的,應該這樣說:Java類只能有一個直接父類,可以有無限多個間接父類,如:
class Fruit extends Plant{…….}
class Apple extends Fruit {…….}
重寫父類的方法:
1、 大部分的時候,子類總是以父類為基礎,額外添加新的屬性和方法。但有一種情況例外:子類需要重寫父類的方法。例如鳥類都包含了飛翔的方法,其中鴕鳥是一種特殊的鳥類,因此鴕鳥也是鳥的子類,因此它也將從鳥類獲得飛翔方法,但這個飛翔方法明顯不適合鴕鳥,為此,鴕鳥需要重寫鳥類的方法。
2、 如下代碼可以幫助理解重寫:
1) class Bird{
2) //Bird類的fly()方法
3) private void fly(){
4) System.out.println("我要在天空中飛翔");
5) }
6) }
7) public class OcerrideTest extends Bird{
8) //重寫Bird類的fly()方法
9) public void fly(){
10) System.out.println("我只能在地上奔跑");
11) }
12) public static void main(String[] args) {
13) //創建OcerrideTest對象
14) OcerrideTest ot = new OcerrideTest();
15) ot.fly();
16) }
17) }
打印結果為:我只能在地上奔跑
這種子類包含父類同名方法的現象被稱為方法重寫,也被稱為方法覆蓋(Override)。
方法的重寫要遵循“兩同兩小一大”規則:
⑴ “兩同”:方法名相同;形參列表相同。
⑵ “兩小”:子類方法之返回類型應比父類方法返回值類型更小或相等;子類方法聲明拋出的異常類應比父類方法聲明拋出的異常類更小或相等。
⑶ 子類方法的訪問權限應比父類方法更大或相等
尤其需要指出的是:覆蓋方法和被覆蓋方法要麽都是類方法,要麽都是實例方法,不能一個是類方法,一個是實例方法,例如下面的代碼將會有編譯錯誤:
Class BaseClass{
public static void test(){…….}
}
Class SubClass extends BaseClass{
public void test(){………….}
}
若想調用父類中的fly()方法,則只需在子類中fly()方法中加上如下代碼即可:
super.fly();
註意:super和this一樣,都不能出現在static的方法中
調用父類構造器
1、看如下程序定義的Basehe Sub類,其中Sub類是Base類的子類,程序在Sub類的構造器中使用super來調用Base構造器裏的初始化代碼。
class Base{
public double size;
public String name;
public Base(double size, String name){
this.size=size;
this.name=name;
}
}
public class Sub extends Base{
public String color;
public Sub(double size, String name, String color){
//在子類構造器中調用父類構造器,使用super調用來實現
super(size,name);
this.color = color;
}
public static void main(String[] args) {
Sub s = new Sub(5.6,"測試對象","紅色");
System.out.println(s.size+"------"+s.name+"------"+s.color);
}
}
打印結果為:5.6------測試對象------紅色
靜態初始化塊
1、如果定義初始化塊時使用了static修飾符,則這個初始化塊,就變成了靜態初始化塊,也被稱作為類初始化塊。靜態初始化塊是類相關的,系統將在類初始化階段執行靜態初始化塊,而不是在創建對象時才執行。因此靜態初始化塊總是比普通初始化塊先執行
封裝的理解:
1、封裝(Encapsulation)是面向對象的三大特征之一,它指的是將對象的狀態信息隱藏在對象內部,不允許外部程序直接訪問對象內部信息,而是通過該類所提供的方法來實現對內部信息的操作和訪問。
2、掌握了訪問控制符的用法之後,下面通過使用合理的訪問控制來定義一個Person類,這個Person類就實現了良好的封裝。代碼如下:
public class Person {
public static void main(String[] args) {
Person p = new Person();
p.setAge(10);
System.out.println(p.getAge());
}
//將屬性使用private修飾,將這些屬性隱藏起來
private String name;
private int age;
//提供方法來操作name屬性
public void setName(String name) {
//對姓名執行合理的校驗
if(name.length() > 6 || name.length() < 2){
System.out.println("您的姓名不符合要求");
}else{
this.name = name;
}
}
public String getName() {
return this.name;
}
//提供方法來操作age屬性
public void setAge(int age) {
if(age>100 || age<0){
System.out.println("您的年齡必須要在0~100之間");
}else{
this.age = age;
}
}
public int getAge() {
return this.age;
}
}
運行結果為:10
多態的理解:
1、多態(Polymorphism)是面向對象的三大特征之一。
2、Java引用變量有兩個類型:一個是編譯時類型,一個是運行時類型。編譯時的類型由聲明該變量時使用的類型決定,運行時的類型由實際賦給該變量的對象決定。如果編譯時類型和運行時類型不一致,就會出現所謂的多態(Polymorphism)
先看下面的程序:
class SuperClass{
public int book = 6;
public void base() {
System.out.println("父類的普通方法base()");
}
public void test(){
System.out.println("父類中北覆蓋的方法");
}
}
public class PloymorphismTest001 extends SuperClass{
//重新定義一個book實例屬性,覆蓋父類的book實例屬性
public String book = "Java瘋狂講義";
public void test() {
System.out.println("子類中覆蓋父類的方法");
}
private void Dmeo() {
System.out.println("子類中普通的方法");
}
//主方法
public static void main(String[] args) {
//下面編譯時類型和運行時類型完全一樣,因此不存在多態
SuperClass sc = new SuperClass();
System.out.println("book1= "+sc.book);//打印結果為:6
//下面兩次調用將執行SuperClass的方法
sc.base();
sc.test();
//下面編譯時類型和運行時類型完全一樣,因此不存在多態
PloymorphismTest001 pt = new PloymorphismTest001();
System.out.println("book2= "+pt.book);//打印結果為:Java瘋狂講義
//下面調用將執行從父類繼承到的base方法
pt.base();
//下面調用將執行當前類的test方法
pt.test();
//下面編譯時類型和運行時類型不一樣,多態發生
SuperClass sscc = new PloymorphismTest001();
//結果表明訪問的是父類屬性
System.out.println("book3= "+sscc.book);//打印結果為:6
//下面調用將執行從父類繼承到得base方法
sscc.base();
//下面調用將執行當前類的test方法
sscc.test();
//因為sscc的編譯類型是SuperClass,SuperClass類沒有提供Demo()方法
//所以下面代碼編譯時會出現錯誤
//sscc.Demo();
}
}
程序運行結果為:
book1= 6
父類的普通方法base()
父類中北覆蓋的方法
book2= Java瘋狂講義
父類的普通方法base()
子類中覆蓋父類的方法
book3= 6
父類的普通方法base()
子類中覆蓋父類的方法
上面程序的main方法中顯示創建而來3個引用變量,對於前兩個引用變量sc和pt,它們編譯時類型和運行時類型完全相同,因此調用它們的屬性和方法非常正常,完全沒有問題。但第三個引用變量sscc,則比較特殊,它編譯時類型是SuperClass ,而運行時類型是PloymorphismTest001,當調用該引用變量的test方法時,實際上是執行PloymorphismTest001類中覆蓋後的test方法,這就是多態。
當把一個子類對象直接賦給父類引用變量,例如上面的SuperClass sscc = new PloymorphismTest001();這個sscc引用變量的編譯時類型是SuperClass,而運行時類型是PloymorphismTest001,當運行時調用該引用變量的方法時,其方法行為總是像子類方法的行為,而不是像父類方法行為,這將出現相同類型的變量、執行同一個方法時呈現出不同的行為特征,這就是多態。
特別提醒:
與方法不同的是,對象的屬性則不具備多態性,如上面的sscc引用變量,程序中輸出它的book屬性時,並不是輸出PloymorphismTest001類裏定義的實例屬性,而是輸出SuperClass類的實例屬性。
註意:
我們通過Object p = new Person()代碼定義一個變量p,則這個p只能調用Object類的方法,而不能調用Person類裏定義的方法。
Java中的繼承、封裝、多態的理解