「Java基礎」6、面向對象 進階

封裝、繼承、多態、接口、抽象類、static、final
6、面向對象 進階

封裝繼承多態-----------java三大特性java

  • 類、接口間關係
    • 類 與 類 之間是:單根繼承
    • 類 與 接口 之間是:多實現
    • 接口 與 接口 之間是:多繼承

1 - 封裝

核心只對須要的類可見用戶無需知道對象內部方法的實現細節,但能夠根據對象提供的外部接口(對象名和參數)訪問該對象程序員

同時也是爲了減小代碼冗餘安全

特性app

​ 安全特性;ide

​ 便於使用特性;性能

​ 提供重複性的特性;測試

好處ui

  1. 隱藏信息和實現細節

經過控制訪問權限能夠將不但願客戶端程序員看見的信息隱藏起來(如客戶的銀行密碼須要保密,便須要只對客戶開放權限)this

  1. 實現了專業的分工

將能實現某一特定功能的代碼封裝成一個單獨的類,在程序員須要使用的時候能夠隨時調用,從而實現了專業的分工code

  1. 提升對象數據的安全性
  • 若是不使用封裝,很容易賦值錯誤,而且任何人均可以更改,形成信息的不安全
  • 封裝之後,設置類的屬性爲private(關鍵字),不能使用對象名.屬性名的方式直接訪問對象的屬性,提升了其安全性。
  • 封裝時,類的屬性private類的方法public

1 - 1 成員的訪問權限

  private default protected public
同一個類 可用 可用 可用 可用
同一個包中的類   可用 可用 可用
子類     可用 可用
其餘包中的類       可用

2 - 繼承(extends)

將多個類具備共同特徵和行爲封裝成一個類,實現一次定義,減小代碼冗餘,實現了代碼複用

一個擁有本身獨特特徵的類(子類 擴展類) 繼承(extends) 擁有共同特徵的類(父類 基類)

子類繼承父類,擁有父類的屬性,於是子類的對象能夠給共同屬性賦值

java中一個類只能繼承一個類(單根繼承)

繼承是一個很廣泛的現象

若是一個類明確指明了繼承(extends)自某一個類,則這個類就是他的父類

若是一個類並未經過extends指明繼承自某一個類,則這個類繼承自Object類(頂級父類---最大的類)

public class Animal { // 父類
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}
public class Dog extends  Animal{ // 子類
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
    
    @Override
    public String toString() {
        return "Dog{" +
                "type='" + type + '\'' +
                "} " + super.toString();
    }

}
public class Cat extends Animal{
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "address='" + address + '\'' +
                "} " + super.toString();
    }
}
public class Main { // 測試類
    public static void main(String[] args) {
        Cat cat = new Cat();
        // 共同特徵(經過繼承獲取)
        cat.setName("hello KiTi"); 
        cat.setAge(3);
        // 獨有特徵
        cat.setAddress("北京");
        System.out.println(cat);
        
        Dog dog  = new Dog();
        // 共同特徵(經過繼承獲取)
        dog.setName("旺財");
        dog.setAge(4);
        // 獨有特徵
        dog.setType("拉布拉多");
        System.out.println(dog);

    }
}

3 - 多態

同一個行爲具備多個不一樣的表現形式。

封裝和繼承多態表現形式

多態實現三個充要條件

  1. 繼承
  2. 重寫父類方法
  3. 父類引用指向子類對象
  • 此處Fruit apple = new Apple();父類的引用指向子類的對象,這即是多態的一種體現(向上轉型),由於Apple繼承與Fruit並重寫了eatFruit(),因此可以表現多種狀態的形式。

  • 向上轉型小範圍 ------> 大範圍

    Fruit apple = new Apple();

  • 動態綁定(自動實現的)

    向上轉型後,用父類的變量接收子類的對象(Fruit apple = new Apple();),運行時會找父類類型變量(apple)中存放數據的實際類型(Apple()),並執行這個實際類(Apple())中的對應方法(eatFruit()),而不是父類(Fruit)中的方法(eatFruit()),用static修飾能夠解決此問題

/**
 * 水果
 */
public class Fruit {
    String fruit; // 

    public String getFruit() {
        return fruit;
    }

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public void eatFruit(){
        System.out.println("吃水果!");
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "fruit='" + fruit + '\'' +
                '}';
    }
}
/**
 * 蘋果
 */
class Apple extends Fruit{

    private String color;   // 顏色

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                "} " + super.toString();
    }

    @Override
    public void eatFruit(){
        color = "紅色";
        super.fruit = "蘋果";
        System.out.println("吃" + color + fruit);
    }

}
/**
 * 橙子
 */
class Orange extends Fruit{
    private String exterior;   // 外觀

    public String getExterior() {
        return exterior;
    }

    public void setExterior(String exterior) {
        this.exterior = exterior;
    }

    @Override
    public void eatFruit() {
        exterior = "圓的";
        super.fruit = "橘子";
        System.out.println("吃" + exterior + fruit);
    }

    @Override
    public String toString() {
        return "Orange{" +
                "exterior='" + exterior + '\'' +
                "} " + super.toString();
    }
}

3 - 1 向上轉型的應用場景

向上轉型會隱藏子類擴展出來的功能

public class Test {
    // 將參數列表改成各類水果的父類,只須要定義一次,就能夠重複利用,而不須要利用方法重寫來實現同一個動做
    public static void DoThing(Fruit fruit){
        System.out.println("---------------------------------------");
        fruit.eatFruit();
        System.out.println("---------------------------------------");
    }
//--------------------方法重寫,會致使代碼冗餘--------------------
    /*public static void DoThing(Orange orange){
        System.out.println("---------------------------------------");
        fruit.eatFruit();
        System.out.println("---------------------------------------");
    }
    public static void DoThing(Apple apple){
        System.out.println("---------------------------------------");
        fruit.eatFruit();
        System.out.println("---------------------------------------");
    }*/
//--------------------------------------------------------------

    }

    public static void main(String[] args) {

        DoThing(new Apple());
        DoThing(new Orange());

    }
}

3 - 2 向下轉型

大範圍 -----> 小範圍 (強制類型轉換):把父類說成子類

向下轉型要求:父類必須擁有子類的屬性不能擁有就會出現類型轉換異常

Apple apple = (Apple) new Fruit();

  • 向下轉型的應用場景

    明確知道了傳入的數據是什麼類型,才能進行向下轉型

    若是要進行向下轉型,必須先向上轉型,在向下轉型,否則會出錯

    public class Test {
        
        public static void main(String[] args) {
            
    //        Apple apple = (Apple) new Fruit(); // 單純的進行強制類型轉換會出現異常
            
            Fruit fruit = DoThing(1);
    
            if (fruit instanceof Orange){
                Orange orange = (Orange) fruit;
                System.out.println(orange);
            }else{
                Apple apple = (Apple) fruit;
                System.out.println(apple);
            }
    
        }
    
        public static Fruit DoThing(int number){
            
            if (number == 0){
                Orange orange = new Orange();
                orange.setFruit("橘子");
                orange.setExterior("圓的");
                return orange;
            }else{
                Apple apple = new Apple();
                apple.setFruit("蘋果");
                apple.setColor("紅色");
                return apple;
            }
        }
    
    }

4 - 組合

組合就是將對象引用置於新類中。

組合也是一種提升代碼複用性的方式。

若是你不想類有更多擴展功能,你須要記住一句話多用組合,少用繼承

  • 組合和繼承是有區別的

    特徵 組合 繼承
    關係 組合是一種has - a的關係,能夠理解爲有一個 繼承是一中 is - a 的關係,能夠理解爲是一個
    耦合性 組合是一種鬆耦合的關係 繼承雙方緊耦合
    是否具備多態 組合不具有多態和向上轉型 繼承是多態的基礎,能夠向上轉型
    時期 組合是運行期綁定 繼承是編譯期綁定
  • Fruit類引用了Apple類、Orange類,從而調用他們各自的屬性和方法

public class Test{
    
    public static void main(String[] args) {
        
        Fruit fruit = new Fruit();
        fruit.setFruit("蘋果"); 

        Apple apple = new Apple();
        apple.setColor("紅的");
        fruit.setApple(apple);

        Orange orange = new Orange();
        orange.setExterior("圓的");
        fruit.setOrange(orange);

        System.out.println(fruit);
        
    }
}
/**
 * 水果
 */
public class Fruit {
    private String fruit;

    private Apple apple;
    private Orange orange;

    public Apple getApple() {
        return apple;
    }

    public void setApple(Apple apple) {
        this.apple = apple;
    }

    public Orange getOrange() {
        return orange;
    }

    public void setOrange(Orange orange) {
        this.orange = orange;
    }

    public String getFruit() {
        return fruit;
    }

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public void eatFruit(){
        System.out.println("吃水果!");
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "fruit='" + fruit + '\'' +
                ", apple=" + apple +
                ", orange=" + orange +
                '}';
    }
}

/**
 * 蘋果
 */
class Apple{

    private String color;   // 顏色

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                '}';
    }
}

/**
 * 橙子
 */
class Orange{
    private String exterior;   // 外觀

    public String getExterior() {
        return exterior;
    }

    public void setExterior(String exterior) {
        this.exterior = exterior;
    }


    @Override
    public String toString() {
        return "Orange{" +
                "exterior='" + exterior + '\'' +
                '}';
    }
}

5 - 接口和抽象類

5 - 1 接口(interface)

由於接口不能被實例化,故接口不能有任何構造方法

若是一個事務只有共同行爲(功能)沒有共同特徵(屬性),則用接口定義

接口注重功能,因此接口中只有方法,且默認爲抽象方法(即默認是用public abstract修飾的)

接口能夠多實現(implements)

// 定義接口
public interface Shape { 
    void area();    // 計算面積
    void perimeter();   // 計算周長
}
// 實現接口
public class Circle implements Shape {

    @Override
    public void area() {
        System.out.println("計算Circle的面積");
    }

    @Override
    public void perimeter() {
        System.out.println("計算Circle的周長");
    }
}

5 - 1 - 1 接口實現解耦合

耦合:個體相互之間有依賴關係

好處:

  1. ​ 便於修改
  2. 業務並行
  3. 分工協做
  4. 通用性強(低耦合)
  • 案例:
public class Test {
    public static void main(String[] args) {
        
        Computer computer = new Computer();
        
        computer.setMainBoard("I7 的主板"); // 同一塊主板可使用不一樣的cpu

        computer.setCpu(new I3());
        computer.getCpu().jiSuan();//調用i3主板的計算功能

        computer.setCpu(new I5());
        computer.getCpu().jiSuan();//i5主板的計算功能

        computer.setCpu(new I7());
        computer.getCpu().jiSuan();//i7主板的計算功能
    }

}
public class Computer {
    private String mainBoard; //主板
    private Cpu cpu; // 至關於電腦預留了一個cpu接口,能夠安裝任意版本

    public String getMainBoard() {
        return mainBoard;
    }

    public void setMainBoard(String mainBoard) {
        this.mainBoard = mainBoard;
    }

    public Cpu getCpu() {
        return cpu;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }


    @Override
    public String toString() {
        return "Computer{" +
                "mainBoard='" + mainBoard + '\'' +
                ", cpu=" + cpu +
                '}';
    }
}
public interface Cpu {    void jiSuan(); // cpu的計算功能}class I3 implements Cpu{    @Override    public void jiSuan() {        System.out.println("I3 Cpu 的計算功能!");    }}class I5 implements Cpu{    @Override    public void jiSuan() {        System.out.println("I5 Cpu 的計算功能!");    }}class I7 implements Cpu{    @Override    public void jiSuan() {        System.out.println("I7 Cpu 的計算功能!");    }}

5 - 2 抽象類(abstract)

抽象類約束沒有接口嚴格,抽象類中能夠定義 構造方法、抽象方法、普通屬性、普通方法、靜態屬性和靜態方法

抽象方法必定存在於抽象類中,但抽象類中不必定有抽象方法,也能夠有具體的方法

抽象類不能建立對象Fruit fruit = new Fruit()會報錯)

public abstract class Fruit{ // 父類,此時父類也是抽象類
    private String fruit;
    
    public String getFruit();

    public void setFruit(String fruit) {
        this.fruit = fruit;
    }

    public abstract void eatFruit(); // 抽象方法
}

class Apple extends Fruit{ // 子類
    private String color;
    
	public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
    
    @Override
    public void eatFruit() { // 必需要添加父類中的行爲,不然會報錯
        System.out.println("吃"+color+"蘋果!");
    }
}

6 - static

在方法區中會獨立分配一塊空間用來存放static修飾的數據,static修飾的東西都會存入其中,而且其中的數據是通用的

java中的關鍵字-----靜態的

能夠修飾屬性和方法

static用在沒有建立對象時調用方法/屬性

  • 靜態成員變量

    能夠修飾全局變量,不能修飾局部變量

    class test{    public static String name = "碼農"; // 能夠修飾全局變量(類變量)        public void Do{		static String name2 = "碼羊"; // 報錯,不能修飾局部變量    }    }
  • 靜態方法

    可使用類名.方法名調用

    static不能修飾 get方法、set方法、構造方法、抽象方法、類

    同一個類中調用類方法,能夠省略類名

    靜態方法中 ** 不能訪問 非靜態方法非靜態成員變量**

    public class Circle implements Shape {
    
        private static Double PI = 3.14; // 靜態成員變量
        private int r; // 非靜態成員變量
    
        // 靜態方法
        public static void area2(){
    //        2*PI*r;  // 報錯,由於此爲靜態方法,而r爲非靜態成員變量
        }
    
        @Override
        public void area() {
            System.out.println(PI*r*r);
        }
    
        @Override
        public void perimeter() {
            System.out.println("計算Circle的周長");
        }
    
    }
  • 靜態代碼快

    用於類的初始化操做,進而提示程序性能

    靜態代碼塊隨着類的加載而執行,所以,不少時候會 只須要 執行一次的初始化操做放在static代碼塊中進行

    public class StaicBlock {
        static{
        	System.out.println("I'm A static code block");
        }
    }

7 - final

最後的,最終的

能夠修飾類、屬性(全局變量和局部變量)、方法

  • final修飾類時

    一旦修飾,表示此類不能被繼承

    成員變量能夠根據須要設定爲final

    注意final中的全部成員方法會隱式的指定爲final方法

  • final修飾方法時

    修飾方法時,表示此方法不能被子類重寫

    只有在明確不但願此方法被子類重寫時纔會將其設定爲final

  • final修飾變量時

    final沒有優先分配的功能,因此必須對其進行賦值(可使用構造代碼塊對其進行賦值,由於構造代碼塊會在構造方法前執行,且調用幾回構造方法,便加載幾回構造代碼塊

    • 修飾基本數據類型

      表示數據類型的值 不能 被改變

      public class Circle implements Shape {
      
          private static Double PI = 3.14;
          private static final Double PII = 3.14;
      
          public static void main(String[] args) {
              PI = 4.5; // 能夠正常修改
      //        PII = 3.5; // 報錯
          }
      }
    • 修飾引用數據類型時

      表示對其初始化後便 不能 在指向另外一個對象

      public class Test {
          public static void main(String[] args) {
              final Fruit fruit = new Fruit();
              fruit.setFruit("蘋果");
              fruit = null; // 報錯:Cannot assign a value to final variable 'fruit'
          }
      }
      
      class Fruit{
          private String fruit;
          
          public String getFruit() {
              return fruit;
          }
      
          public void setFruit(String fruit) {
              this.fruit = fruit;
          }
      }
相關文章
相關標籤/搜索