1. 程式人生 > >Java三大特性詳解

Java三大特性詳解

Java的三大特性詳解

封裝

封裝的定義

封裝(Encapsulation)是面向物件方法的重要原則,就是把物件的屬性和操作(或服務)結合為一個獨立的整體,並儘可能隱藏物件的內部實現細節。

封裝的好處

  1. 良好的封裝能夠減少耦合。
  2. 類內部的結構可以自由修改。
  3. 可以對成員進行更精確的控制。
  4. 隱藏資訊,實現細節。

    public class Person{
        private String name;
        private int age;
        private String sex;
    
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
        private int getAge(){
            return age;
        }
        private void setAge(int age){
            this.age = age;
        }
        public void setSex(String sex){
            this.sex = sex;
        }
    }
    

    如果沒有setter(),getter()的話,那麼Person類應該是這樣的:

    public class Person {  
        public String name ;  
        public String sex ;  
        public int age ;   
    }
    

    我們應該這樣使用它:

    Person person = new Person();  
    person.age = 25;  
    person.name = "張三";  
    person.sex = "男";
    

    但是如果需要修改Person,比如將sex修改為int型別,幾十或者上百個這樣的地方估計要改到崩潰,如果封裝了,只需要修改setSex()方法就好了。另外,封裝確實可以使我們容易地修改類的內部實現,而無需修改使用了該類的客戶程式碼。還有針對某些成員變數,不想讓其他類知道值為多少,就可以不去做getter()操作,比如Person類中的sex,不想讓其他人知道性別,就不做getSex()。還有就是private修飾的成員變數以及成員函式,只能無法在類外呼叫,做到隱藏的作用。比如:Person類中的成員變數以及getAge()和setAge()在其他類是無法獲取到的。

    public class Person{
        private String name;
        private int age;
        private int sex;//1:男;2:女;0:保密
    
        public String getName(){
            return name;
        }
        public void setName(String name){
            this.name = name;
        }
        private int getAge(){
            return age;
        }
        private void setAge(int age){
            this.age = age;
        }
        public void setSex(String sex){
            if(StringUtils.isNotEmpty(sex)){
                if(sex.equals('男')){
                    this.sex = 1;
                }else if(sex.equals('女')){
                    this.sex = 2;                   
                }else{
                    this.sex = 0;
                }
            }else{
                System.out.println("請輸入性別!");    //提示錯誤資訊
            }
        }
    }
    

繼承

繼承的定義

繼承是面向物件最顯著的一個特性。繼承是從已有的類中派生出新的類,新的類能吸收已有類的資料屬性和行為,並能擴充套件新的能力。關鍵字(extends)讓類與類之間產生繼承關係。

//Man是子類,Person是父類
class Man extends Person{}

繼承的特點

  1. 繼承關係是傳遞的。若類C繼承類B,類B繼承類A(多層繼承),則類C既有從類B那裡繼承下來的屬性與方法,也有從類A那裡繼承下來的屬性與方法,還可以有自己新定義的屬性和方法。繼承來的屬性和方法儘管是隱式的,但仍是類C的屬性和方法。繼承是在一些比較一般的類的基礎上構造、建立和擴充新類的最有效的手段。
  2. 提供多重繼承機制。從理論上說,一個類可以是多個一般類的特殊類,它可以從多個一般類中繼承屬性與方法,這便是多重繼承。Java出於安全性和可靠性的考慮,僅支援單重繼承,而通過使用介面機制來實現多重繼承。
  3. 提高程式碼的複用性。若類B繼承類A,那麼建立類B時只需要再描述與基類(類A)不同的少量特徵(資料成員和成員方法)即可。這種做法能減小程式碼和資料的冗餘度,大大增加程式的重用性。
  4. Java只支援單繼承,不支援多繼承。也就是一個類只能有一個父類,不可以有多個父類。

super和this的區別

  1. super(引數)是呼叫基類中的某一個建構函式(建構函式的第一條語句);this(引數)是呼叫本類中另一種形成的建構函式(建構函式中的第一條語句)
  2. super引用當前物件的直接父類中的成員(用來訪問直接父類中被隱藏的父類中成員資料或者函式,基類與派生類中有相同成員定義時如:super.變數名 super.成員函式名(實參));this代表當前物件名(在程式中產生二義性之處,應使用this來指明當前物件;如果函式的形參與類中的成員資料同名,這時需要用this來指明成員變數名)
  3. 呼叫super()必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地呼叫super(),如果父類沒有這種形式的建構函式,那麼在編譯的時候就會報錯。
  4. super()和this()類似,區別是,super()從子類中呼叫父類的構造方法,this()在同一類內呼叫其它方法。
  5. super()和this()均需放在構造方法內第一行。
  6. 儘管可以用this呼叫一個構造器,但卻不能呼叫兩個。
  7. this和super不能同時出現在一個建構函式裡面,因為this必然會呼叫其它的建構函式,其它的建構函式必然也會有super語句的存在,所以在同一個建構函式裡面有相同的語句,就失去了語句的意義,編譯器也不會通過。
  8. this()和super()都指的是物件,所以,均不可以在static環境中使用。包括:static變數,static方法,static語句塊。
  9. 從本質上講,this是一個指向本物件的指標, 然而super是一個Java關鍵字。

內部類

將一個類定義在另一個類裡面,裡面的那個類就稱為內部類。內部類的出現,再次打破了Java單繼承的侷限性。

訪問特點:
  • 內部類可以直接訪問外部類的成員,包括私有成員。
  • 外部類要訪問內部類的成員,必須要建立內部類的物件。
內部類分類及共性:

1. 共性

  • 內部類仍然是一個獨立的類,在編譯之後會內部類會被編譯成獨立的.class檔案,但是前面冠以外部類的類名和$符號。
  • 內部類不能用普通的方式訪問。內部類是外部類的一個成員,因此內部類可以自由地訪問外部類的成員變數,無論是否是private的。

2. 成員內部類

在外部類中有成員變數和成員方法,成員內部類就是把整個一個類作為了外部類的成員;

成員內部類是定義在類中方法外的類;

建立物件的格式為:外部類名.內部類名 物件名 = 外部類物件.內部類物件;

成員內部類之所以可以直接訪問外部類的成員,那是因為內部類中都持有一個外部類物件的引用:外部類名.this;

成員內部類可以用的修飾符有final,abstract,public,private,protected,static.

3. 靜態內部類

靜態內部類就是成員內部類加上靜態修飾符static,定義在類中方法外。

在外部類中訪問靜態內部類有兩種場景:

  • 在外部類中訪問靜態內部類中非靜態成員:外部類名.內部類名 物件名 = 外部類名.內部物件,需要通過建立物件訪問;
  • 在外部類中訪問靜態內部類中的靜態成員:同樣可以使用上面的格式進行訪問,也可以直接使用外部類名.內部類名.成員。

4. 區域性內部類

區域性內部類是定義在方法中的類。

  • 方法內部類只能在定義該內部類的方法內例項化,不可以在此方法外對其例項化。
  • 方法內部類物件不能使用該內部類所在方法的非final區域性變數。

可以用於方法內部類的修飾符有final,abstract;

靜態方法中的方法內部類只能訪問外部的靜態成員。

5. 匿名內部類

匿名內部類是內部類的簡化寫法,是建立一個帶內容的外部類或者介面的子類匿名物件。

前提:

內部類可以繼承或實現一個外部類或者介面。

格式:

  • new 外部類名或者介面名(){重寫方法};
  • 通常在方法的形式引數是介面或者抽象類,並且該介面中的方法不超過三個時,可以將匿名內部類作為引數傳遞。

多型

多型的定義

物件在不同時刻表現出來的不同狀態。

多型的注意事項

  • 一定不能夠將父類的物件轉換成子類型別。
  • 多型自始至終都是子類物件在變化。
  • 父類的引用指向子類物件,該引用可以被提升,也可以被強制轉換。

重寫與過載

方法的重寫Overriding和過載Overloading是Java多型性的不同表現。重寫Overriding是父類與子類之間多型性的一種表現,過載Overloading是一個類中多型性的一種表現。

重寫遵循以下規則:

  • 引數列表必須完全和被重寫方法的引數列表一致。
  • 返回型別必須完全和被重寫方法的返回型別一致。
  • 訪問修飾符的限制一定要大於被重寫方法的訪問修飾符(public>protected>default>private)。
  • 重寫的方法一定不能丟擲新的檢查異常或者比被重寫方法宣告更加寬泛的檢測型異常。

過載的注意事項:

  • 在使用過載時只能通過相同的方法名、不同的引數形式實現。不同的引數型別可以是不同的引數型別,不同的引數個數,不同的引數順序(引數型別必須不一樣)。
  • 各個過載方法的引數列表必須不同。
  • 各個過載方法的返回值型別可以相同也可以不同,但是僅僅返回值型別不同的不是過載。
  • 不能通過僅僅通過訪問許可權、返回型別、丟擲的異常的不同而進行過載

不同修飾符修飾的內容

             類       成員變數   成員方法        構造方法

private                Y          Y            Y
default       Y        Y          Y            Y
protected              Y          Y            Y
public        Y        Y          Y            Y
abstract      Y                   Y  
static                 Y          Y            Y
final         Y        Y          Y  

注意,常見規則如下:

  • 以後,所有的類都用public修飾。並且,在一個java檔案中,只寫一個類。
  • 以後,所有的成員變數用private修飾。
  • 以後,所有的成員方法用public修飾。
  • 如果是抽象類或者介面:public abstract + …
  • 以後,所有的構造方法用public修飾。
  • 如果類是工具類或者單例類:構造用private修飾

抽象

抽象的定義

抽象就是從多個事物中將共性的,本質的內容抽象出來。

抽象類

Java中可以定義沒有方法體的方法,該方法的具體實現由子類完成,該方法稱為抽象方法,包含抽象方法的類就是抽象類。

由來:

多個物件都具備相同的功能,但是功能具體內容有所不同,那麼在抽取過程中,只抽取了功能定義,並未抽取功能主體,那麼只有功能宣告,沒有功能主體的方法稱為抽象方法。

抽象類特點:
  • 抽象方法一定在抽象類中;
  • 抽象方法和抽象類都必須被abstract關鍵字修飾;
  • 抽象類不可以用new建立物件,因為呼叫抽象方法沒意義;
  • 抽象類中的抽象方法要被使用,必須由子類複寫其所有的抽象方法後,建立子類物件呼叫; 如果子類只覆蓋了部分的抽象方法,那麼該子類還是一個抽象類;
  • 抽象類中可以有抽象方法,也可以有非抽象方法,抽象方法用於子類例項化;
  • 如果一個類是抽象類,那麼,繼承它的子類,要麼是抽象類,要麼重寫所有抽象方法。
  • 特殊:抽象類中可以不定義抽象方法,這樣做僅僅是不讓該類建立物件。
抽象類的成員特點:
  • 成員變數:可以是變數,也可以是常量;
  • 構造方法:有構造方法;
  • 成員方法:可以是抽象方法,也可以是非抽象方法。
抽象類注意事項:

1. 抽象類不能被例項化,為什麼還有建構函式?

只要是class定義的類裡面就肯定有建構函式。抽象類中的函式是給子類例項化的。

2. 一個類沒有抽象方法,為什麼定義為抽象類?

不想被繼承,還不想被例項化。

3. 抽象關鍵字abstract不可以和哪些關鍵字共存?

  • final:如果方法被抽象,就需要被覆蓋,而final是不可以被覆蓋,所以衝突。
  • private:如果函式被私有了,子類無法直接訪問,怎麼覆蓋呢?
  • static:不需要物件,類名就可以呼叫抽象方法。而呼叫抽象方法沒有意義。

介面(interface)

介面的定義

介面是抽象方法和常量值的集合。從本質上講,介面是一種特殊的抽象類,這種抽象類只包含常量和方法的定義,而沒有變數和方法的實現。

格式:interface 介面名{}

介面的出現將”多繼承“通過另一種形式體現出來,即”多實現“。

實現(implements)

格式:class 類名 implements 介面名 {}

介面特點

  • 介面不能被例項化。
  • 一個類如果實現了介面,要麼是抽象類,要麼實現介面中的所有方法。

介面的成員特點:

介面中的成員修飾符是固定的!

  • 成員常量:public static final,接口裡定義的變數是全域性常量,而且修飾符只能是這三個關鍵字,都可以省略,常量名要大寫。
  • 成員方法:public abstract,接口裡定義的方法都是抽象的,兩個修飾符關鍵字可省略。
  • 推薦:永遠手動給出修飾符。

繼承與實現的區別:

  • 類與類之間稱為繼承關係:因為該類無論是抽象的還是非抽象的,它的內部都可以定義非抽象方法,這個方法可以直接被子類使用,子類繼承即可。只能單繼承,可以多層繼承。((class))
  • 類與介面之間是實現關係:因為介面中的方法都是抽象的,必須由子類實現才可以例項化。可以單實現,也可以多實現;還可以在繼承一個類的同時實現多個介面。((class) extends (class) implements (interface1,interface2…))
  • 介面與介面之間是繼承關係:一個介面可以繼承另一個介面,並新增新的屬性和抽象方法,並且介面可以多繼承。((interface) extends (interface1,interface2…))

抽象類和介面的區別:

成員變數

  • 抽象類能有變數也可以有常量
  • 介面只能有常量

成員方法

  • 抽象類可以有非抽象的方法,也可以有抽象的方法
  • 介面只能有抽象的方法

構造方法

  • 抽象類有構造方法
  • 介面沒有構造方法

類與抽象類和介面的關係

  • 類與抽象類的關係是繼承 extends
  • 類與介面的關係是實現 implements

介面的思想特點:

  1. 介面是對外暴露的規則;
  2. 介面是程式的功能擴充套件;
  3. 介面的出現降低耦合性;(實現了模組化開發,定義好規則,每個人實現自己的模組,大大提高了開發效率)
  4. 介面可以用來多實現;
  5. 多個無關的類可以實現同一個介面;
  6. 一個類可以實現多個相互直接沒有關係的介面;
  7. 與繼承關係類似,介面與實現類之間存在多型性。

參考文件