1. 程式人生 > >面向物件程式設計:封裝,繼承,多型

面向物件程式設計:封裝,繼承,多型

面向物件的三大特徵:封裝,繼承,多型

封裝

封裝概述

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

類是Java中最小的一個單位,它體現了一種封裝的思想,封裝了成員變數(屬性)和成員方法(功能)
如何定義一個類

class 類名{
成員變數
成員方法(){
}
}

如何使用類
類是一個很抽象的概念,無法直接使用,若想使用該類,需要先對其進行例項化,即建立該類的物件,物件時該類的具體表現
** 如何建立物件**
使用 new關鍵字就可以建立該類物件
格式

類名 物件名 = new 類名();

比如說現在有一個student

Student   s=new Student()

方法

Java方法是語句的集合,它們在一起執行一個功能
方法的定義

修飾符 返回值型別 方法名(引數型別 引數名){
    ...
    方法體
    ...
    return 返回值;
}
  • 修飾符:是可選的,它定義了方法的訪問型別。
  • 返回返回型別:void是指沒有沒有特定的返回值,但如果改為其他的例如int ,double那麼就一定要有一個返回值了
  • 方法名:是該方法的名字,由大家自己定義
  • 引數型別:聲明瞭引數的資料型別,例如第一個例子中的int表示引數是int型別
  • 引數名:引數的名字,例如第一個程式碼例子中的a和b就是引數的名字
  • 方法體:該方法具體想實現的功能
  • return:結束方法,並返回指定的型別
  • 返回值:方法的結果,由return帶回
    ** 方法的呼叫**
    Java 支援兩種呼叫方法的方式,根據方法是否返回值來選擇。當程式呼叫一個方法時,程式的控制權交給了被呼叫的方法。當被呼叫方法的返回語句執行或者到達方法體閉括號時候交還控制權給程式。
    1.當方法返回一個值的時候,方法呼叫通常被當做一個值
    2.如果方法返回值是void,方法呼叫一定是一條語句。
    例:
class demo1{
    public static void main(String[] args) {
        test1();
        System.out.println(test2());
    }
    public static void test1() {
        System.out.println("你好世界");
    }
    public static int test2(){
        return 2;
    }
}

通過值傳遞引數
在定義方法時,如果定義了形式引數,那麼在呼叫時就要提供引數,要按照引數列表所給定的順序傳入

 public static void test(int a,String b){
        System.out.println(b+"-----------"+a);
    }

此方法在呼叫時就需要傳入兩個引數,第一個是int型別的,第二個是String型別的

test2(5,"name");

** 方法過載**
方法過載是指在一個類中定義多個同名的方法,但要求每個方法具有不同的引數的型別或引數的個數,方法過載與返回值型別,返回值,引數名都沒有關係。
構造方法
語法
方法名和類名相同,沒有返回值型別,連void都沒有。根據方法有無引數,我們將其分為有參構造方法和無參構造方法,在我們定義的類中都會有一個預設的無參構造
舉例

public Student(){
	System.out.println("這是一個無參構造");
}
public Student(){
	System.out.println("這是一個有參構造");
	this.name=name;
}

注意:在一個類中,如果寫了一個有參構造,那麼就不會有預設的無參構造方法了,如果要用到無參構造方法需要自己寫一個。
作用
用來完成對類的初始化

程式碼塊

** 概述**
在Java中,使用{}括起來的程式碼被稱為程式碼塊。
區域性程式碼塊
在方法中出現;限定變數生命週期,及早釋放,提高記憶體利用率
舉例

public class demo {
    public static void main(String[] args) {
        { 
            int x = 3;
            System.out.println("普通程式碼塊內的變數x=" + x);
        }
        int x = 1;
        System.out.println("主方法內的變數x=" + x);
        
    }
} 

構造程式碼塊
在類中方法外出現;多個構造方法方法中相同的程式碼存放到一起,每次呼叫構造都執行,並且在構造方法前執行
舉例

class test{
    public test(){
        System.out.println("這是一個無參構造方法");
    }
    public test(int a){
        System.out.println("這是一個有參構造方法,引數是a,a="+a);
    }
}
public class demo {
    public static void main(String[] args) {
        new test();
        new test(5);
    }
}

靜態程式碼塊
在類中方法外出現,並加上static修飾;用於給類進行初始化,在載入的時候就執行,並且只執行一次。
舉例

class test{
    public test(){
        System.out.println("這是一個無參構造方法");
    }
    public test(int a){
        System.out.println("這是一個有參構造方法,引數是a,a="+a);
    }
    static {
        System.out.println("test的靜態程式碼塊");
    }
}
public class demo {
    public static void main(String[] args) {
        new test();
        new test(5);
    }
}

封裝的好處

1.物件的資料封裝特性徹底消除了傳統結構方法中資料與操作分離所帶來的種種問題,提高了程式的可複用性和可維護性,降低了程式設計師保持資料與操作內容的負擔。
2.物件的資料封裝特性還可以把物件的私有資料和公共資料分離開,保護了私有資料,減少了可能的模組間干擾,達到降低程式複雜性、提高可控性的目的

繼承

繼承概述

繼承是面向物件最顯著的一個特性,Java繼承是使用已存在的類的定義作為基礎建立新類的技術,新類的定義可以增加新的資料或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。關鍵字:extent
** 繼承的格式**

class 子類名 extent  父類名{
}

** 繼承的注意事項**
1.父類私有成員無法被繼承(private修飾的)
2.構造方法不參與繼承
3.Java中不支援多繼承,但支援多層繼承
4.不要為了一小部分功能使用繼承,這會增加程式碼的耦合性
這與程式碼開發規則:高內聚,低耦合 相悖

關鍵字this與super

this 代表本類的一個引用,可以理解為本類的一個物件,誰呼叫就代表誰
super 是父類空間的標識,可以理解為父類的一個物件
this的用法
1.普通的直接引用
這種就不用講了,this相當於是指向當前物件本身
2.形參與成員名字重名,用this來區分:

class Person {
    private int age = 10;
    public Person(){
    System.out.println("初始化年齡:"+age);
}
    public int GetAge(int age){
        this.age = age;
        return this.age;
    }
}
 
public class test1 {
    public static void main(String[] args) {
        Person Harry = new Person();
        System.out.println("Harry's age is: "+Harry.GetAge(12));
    }
}       

輸出為

初始化年齡:10
Harry's age is:12

3.引用建構函式
放在下面和super一起看
super用法
1.值接引用
指向當前物件的父類,super.XXX表示父類的成員
2.子類中的變數和方法與父類中的重名
例如:

 class people {
    String name;
    public void demo(){
        name="小剛";
    }
}
class student extends people{
    String name="小明";
    public void demo() {
        super.demo();//呼叫父類方法
        System.out.println(name);
        System.out.println(super.name);
    }

    public static void main(String[] args) {
        student st= new student();
        st.demo();
    }
}

執行結果

小明
小剛

3.引用建構函式
super(引數):呼叫父類中的某一個建構函式(應該為建構函式中的第一條語句)。
this(引數):呼叫本類中另一種形式的建構函式(應該為建構函式中的第一條語句)。

class Person { 
    public static void prt(String s) { 
       System.out.println(s); 
    } 
   
    Person() { 
       prt("父類·無引數構造方法: "+"A Person."); 
    }//構造方法(1) 
    
    Person(String name) { 
       prt("父類·含一個引數的構造方法: "+"A person's name is " + name); 
    }//構造方法(2) 
} 
    
public class Chinese extends Person { 
    Chinese() { 
       super(); // 呼叫父類構造方法(1) 
       prt("子類·呼叫父類”無引數構造方法“: "+"A chinese coder."); 
    } 
    
    Chinese(String name) { 
       super(name);// 呼叫父類具有相同形參的構造方法(2) 
       prt("子類·呼叫父類”含一個引數的構造方法“: "+"his name is " + name); 
    } 
    
    Chinese(String name, int age) { 
       this(name);// 呼叫具有相同形參的構造方法(3) 
       prt("子類:呼叫子類具有相同形參的構造方法:his age is " + age); 
    } 
    
    public static void main(String[] args) { 
       Chinese cn = new Chinese(); 
       cn = new Chinese("codersai"); 
       cn = new Chinese("codersai", 18); 
    } 
}

繼承的中構造方法
繼承中建構函式的關係
子類中所有的構造方法預設都會訪問父類中空引數的構造方法。這是因為子類會繼承父類中的資料,可能還會使用父類的資料。所以,子類初始化之前,一定要先完成父類資料的初始化,每一個構造方法的第一條語句預設都是:super(),這一點在上面的super和this的用法中也有提到
** 繼承中構造方法的注意事項**
如果父類沒有無參構造方法,子類初始化怎麼辦?
1. 在父類中新增一個無參的構造方法
2.子類通過super去顯示呼叫父類其他的帶參的構造方法
3.子類通過this去呼叫本類的其他構造方法,本類其他構造也必須首先訪問了父類構造
注意事項
super(…)或者this(….)必須出現在第一條語句上,這在上面的super和this的用法中也有提到
** 方法重寫**
當父類和子類的方法申明(方法名,返回值型別,引數列表)一樣時,子類的方法就會覆蓋掉父類的方法,這樣的現象稱之為方法重寫。當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法。這樣,即沿襲了父類的功能,又定義了子類特有的內容。
舉例

class animal{
    int age;
    public void eat(){
        System.out.println("吃東西");        
    }
}
class cat extends animal{
    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }
}
class dog extends animal{
    public void eat() {
        System.out.println("狗吃肉");
    }
}

方法重寫的注意事項
1.父類中私有方法不能被重寫,因為父類私有方法子類根本就無法繼承
2.:子類重寫父類方法時,訪問許可權不能更低最好就一致
(四個許可權修飾符 public> (空缺的,什麼都不寫) >protect>private )
3.靜態方法不參與重寫

final關鍵字

** final用法**
由於繼承中有一個方法重寫的現象,而有時候我們不想讓子類去重寫父類的方法.這對這種情況java就給我們提供了一個關鍵字: final
final可以修飾類,成員方法,變數

final class demo {
    final  int a=100;//變數變為常量
    public final void show(){
    } //該該方法無法被重寫
}//該類無法被繼承

** final修飾特點**
修飾類: 被修飾類不能被繼承
修飾方法: 被修飾的方法不能被重寫
修飾變數: 被修飾的變數不能被重新賦值,因為這個量其實是一個常量
修飾引用型別:其地址無法被修改

繼承的優點與弊端

優點
1.提高了程式碼的複用性
2.提高了程式碼的維護性
3.讓類與類之間產生了關係,是多型的前提
弊端
增加了程式碼的耦合性,這違背可開發的原則:高內聚,低耦合

多型

多型概述

在面嚮物件語言中,介面的多種不同的實現方式即為多型,簡單的說,就是允許將子類型別的指標賦值給父類型別的指標。

Cat c=new Cat();
Animal a=new Cat();

多型存在的必要條件

1.繼承
2.方法重寫
3.父類引用指向子類

多型中成員訪問特點

1.成員變數:編譯看左邊,執行看左邊
2.構造方法:建立子類物件的時候,會訪問父類的構造方法,對父類的資料進行初始化。
3.成員方法:編譯看左邊,執行看右邊。
4.靜態方法:編譯看左邊,執行看左邊。
(靜態和類相關,算不上重寫,所以,訪問還是左邊的)

class Super {
	int index = 5;
	public void printVal() {
		System.out.println("Super");
	}
}
class Sub extends Super {
	int index = 2;
	public void printVal(){
		System.out.println("Sub");
	}
}
class Demo {
	public static void main(String[] args) {
		Super sup = new Sub();
		System.out.print(sup.index + ",");//成員變數:編譯看左邊,執行看左邊
		sup.printVal();//成員方法:編譯看左邊,執行看右邊
	}
}

多型的優點以及弊端

優點
1.提高了程式碼的維護性(繼承保證)
2.提高了程式碼的擴充套件性(由多型保證)
弊端
不能使用子類特有的功能

向下轉型

把父類的引用強制轉換為子類的引用。用來解決多型的弊端
舉例

public class MyTest{
    public static void main(String[] args) {
        Fu fu = new Zi();
        System.out.println(fu.num);
        fu.show();
        Zi zi= (Zi) fu;//向下轉型
        System.out.println(zi.num);
        zi.mehtod();
    }

}

class Fu{
    int num=100;
    public void show(){
        System.out.println("fu  show");
    }
}
class Zi extends Fu{
    int num=10;

    @Override
    public void show() {
        System.out.println("zi show");
    }
    public void mehtod(){
        System.out.println("子類特有的方法");
    }
}