封裝、繼承、多態-----------java三大特性java
核心:只對須要的類可見,用戶無需知道對象內部方法的實現細節,但能夠根據對象提供的外部接口(對象名和參數)訪問該對象程序員
同時也是爲了減小代碼冗餘安全
特性:app
安全特性;ide
便於使用特性;性能
提供重複性的特性;測試
好處:ui
- 隱藏信息和實現細節
經過控制訪問權限能夠將不但願客戶端程序員看見的信息隱藏起來(如客戶的銀行密碼須要保密,便須要只對客戶開放權限)this
- 實現了專業的分工
將能實現某一特定功能的代碼封裝成一個單獨的類,在程序員須要使用的時候能夠隨時調用,從而實現了專業的分工code
- 提升對象數據的安全性
private | default | protected | public | |
---|---|---|---|---|
同一個類 | 可用 | 可用 | 可用 | 可用 |
同一個包中的類 | 可用 | 可用 | 可用 | |
子類 | 可用 | 可用 | ||
其餘包中的類 | 可用 |
將多個類具備共同特徵和行爲封裝成一個類,實現一次定義,減小代碼冗餘,實現了代碼的複用性
一個擁有本身獨特特徵的類(子類 擴展類) 繼承(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); } }
同一個行爲具備多個不一樣的表現形式。
封裝和繼承是多態的表現形式
多態實現的三個充要條件:
- 繼承
- 重寫父類方法
- 父類引用指向子類對象
此處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(); } }
向上轉型會隱藏子類擴展出來的功能
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()); } }
大範圍 -----> 小範圍 (強制類型轉換):把父類說成是子類
向下轉型要求:父類必須擁有子類的屬性,不能擁有就會出現類型轉換異常
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; } } }
組合就是將對象引用置於新類中。
組合也是一種提升代碼複用性的方式。
若是你不想讓類有更多的擴展功能,你須要記住一句話多用組合,少用繼承
組合和繼承是有區別的
特徵 | 組合 | 繼承 |
---|---|---|
關係 | 組合是一種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 + '\'' + '}'; } }
由於接口不能被實例化,故接口中不能有任何構造方法
若是一個事務只有共同行爲(功能)而沒有共同特徵(屬性),則用接口定義
接口注重功能,因此接口中只有方法,且默認爲抽象方法(即默認是用
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的周長"); } }
耦合:個體相互之間有依賴關係
好處:
- 便於修改
- 業務並行
- 分工協做
- 通用性強(低耦合)
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 的計算功能!"); }}
抽象類約束沒有接口嚴格,抽象類中能夠定義 構造方法、抽象方法、普通屬性、普通方法、靜態屬性和靜態方法
抽象方法必定要存在於抽象類中,但抽象類中不必定有抽象方法,也能夠有具體的方法
抽象類不能建立對象(
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+"蘋果!"); } }
在方法區中會獨立分配一塊空間用來存放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"); } }
最後的,最終的
能夠修飾類、屬性(全局變量和局部變量)、方法
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; } }