Java 三大特性,算是Java獨特的表現,提到Java 的三大特性, 我們都會想到封裝, 繼承和多態 這是我們Java 最重要的特性。
封裝(Encapsulation) :
封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。
好處:
• 將變化隔離。
• 便於使用。
• 提高重用性。
• 提高安全性。
封裝原則:
• 將不需要對外提供的內容都隱藏起來。
• 把屬性都隱藏,提供公共方法對其訪問 。
private關鍵字:
• 是一個權限修飾符。
• 用於修飾成員(成員變量和成員函數)
• 被私有化的成員只在本類中有效。
常用之一:
將成員變量私有化,對外提供對應的set , get方法對其進行訪問。提高對數據訪問的安全性。
舉個栗子:
我們常說的失血模型
1 public class Demo { 2 3 private String name; 4 private String sex ; 5 private int age; 6 public String getName() { 7 return name; 8 } 9 public void setName(String name) { 10 this.name = name; 11 } 12 public String getSex() { 13 return sex; 14 } 15 public void setSex(String sex) { 16 this.sex = sex; 17 } 18 public int getAge() { 19 return age; 20 } 21 public void setAge(int age) { 22 this.age = age; 23 } 24 25 26 }
構造代碼塊和構造方法(Construct):
構造方法:
用於給對象進行初始化,是給與之對應的對象進行初始化,它具有針對性,函數中的一種。
特點:
- 該函數的名稱和所在類的名稱相同。
- 不需要定義返回值類型。
- 該函數沒有具體的返回值。
- 構造函數並不是由我們手動調用的(手動調用指的是如b1.baby();),而是在創建對應的對象時,JVM就會主動調用到對應的構造函數。
- 如果一個類沒有顯式的寫上一個構造方法時,那么Java編譯器會為該類添加一個無參的構造函數的。
- 如果一個類已經顯式的寫上一個構造方法時,那么Java編譯器則不會再為該類添加一個無參的構造方法。
- 構造函數是可以在一個類中以函數重載的形式存在多個的。
- 構造方法有無參構造方法和有參構造方法。無參構造方法JVM 默認創建一個,如果手動創建了有參構造方法,那么系統會默認識別有參構造方法。
構造函數的定義格式: 修飾符 函數名(形式參數){ 函數體; }
修飾符 函數名(){
函數體;
}
構造方法與普通方法的區別:
(1)返回值類型的區別:
①構造函數是沒有返回值類型的,如果加上void或者別的返回值類型,就變成一個普通的函數,就需要我們手動去調用。
②普通函數是有返回值類型的,即使函數沒有返回值,返回值類型也要寫上void。
(2)函數名的區別:
①構造函數的函數名必須要與類名一致。
②普通函數的函數名只要符合標識符的命名規則即可。
(3)調用方式的區別:
①構造函數是在創建對象的時候由JVM調用的。
②普通函數是由我們使用對象調用的,一個對象可以調用多次普通的函數。
(4)作用上的區別:
①構造函數的作用用於初始化一個對象。每創建一個對象就會有一個初始值。
②普通函數是用於描述一類事物的公共行為的。
注意事項:
(1)Java編譯器添加的無參的構造方法的權限修飾符與類的權限修飾符是一致的。
(2)構造函數是創建對象的時候調用的,所以就可以把屬性值傳到構造函數中,在構造函數中設置參數接收屬性值。
(3)JVM和Java編譯器是不同的,Java編譯器編譯生成的.class文件是給JVM看的,所以經過編譯后的class類打開后會是亂碼,我們可以通過反編譯來查看。
構造代碼塊:
1.構造代碼塊的作用與構造函數的作用的對比:
(1)構造代碼塊的作用:給所有對象進行統一的初始化,對象一建立就運行並且優先於構造函數,比如所有的嬰兒出生都會哭。
(2)構造函數的作用:給對應的對象(new )進行初始化。
1 構造代碼塊的格式: 2 3 { 4 5 構造代碼塊; 6 7 }
注意:構造代碼塊的大括號必須位於成員的位置上。
代碼塊的類別:
(1)構造代碼塊:在工作中經常會用到。
(2)局部代碼塊:大括號位於方法之內,基本上寫不寫沒什么區別,現實開發中也很少會用到。它的作用是縮短局部變量的生命周期,節省一點點內存。
(3)靜態代碼塊:使用static修飾的代碼塊。
注意的事項:
(1)Java編譯器在編譯一個Java源文件的時候,會把成員變量的聲明語句提前至一個類的最前端。
(2)成員變量的初始化工作其實都是在構造函數中執行的。
(3)一旦經過Java編譯器編譯后,那么構造代碼塊的代碼就會被移動到構造函數中執行,構造代碼塊的代碼是在構造函數之前執行的,構造函數中的代碼是最后執行的。
(4)成員變量的顯示初始化與構造代碼塊的代碼是按照當前代碼的順序執行的。
繼承(inheritance):
繼承是面向對象最顯著的一個特性。 繼承是從已有的類中派生出新的類, 新的類能吸收已有類的數據屬性和行為,並能擴展新的能力。
在JAVA中, 被繼承的類叫父類(parent class)或超類(superclass), 繼承父類的類叫子類(subclass)或派生類(derivedclass)。 因此, 子類是父類的一個專門用途的版本, 它繼承了父類中定義的所有實例變量和方法, 並且增加了獨特的元素 。
繼承的結構:
繼承的使用 :
關鍵字:extends。
1 使用繼承 2 – 編寫父類 3 – 編寫子類, 繼承父類 4 class Animal { 5 //公共的屬性和方法 6 } 7 class Chicken extends Animal{ 8 //子類特有的屬性和方法 9 } 10 class Duck extends Animal { 11 }
基本語法:
1 基本語法 2 3 class Chicken extends Animal{ } 4 5 上述代碼表示Chicken類繼承Animal類,使用extends關鍵詞將Animal類(父類/超類)和Chicken類(子類)連接接起來; 6 在繼承關系下,Chicken類將擁有Animal類所有的非私有的方法和屬性,Chicken類還可以擁有自己獨有的方法和屬性; 7 聲明Animal類,實例化Chicken類時, Chicken類會自動向上轉型為Animal類;
舉個栗子:
1 //創建動物類 2 3 public class Animal { 4 private String type; 5 private String skin; 6 private int legCount; 7 public void eat(){ 8 System.out.println("動物正在吃東西"); 9 } 10 public void breath(){ 11 System.out.println("動物正在呼吸"); 12 } 13 public String getType() { 14 return type; 15 } 16 public void setType(String type) { 17 this.type = type; 18 } 19 public String getSkin() { 20 return skin; 21 } 22 public void setSkin(String skin) { 23 this.skin = skin; 24 } 25 public int getLegCount() { 26 return legCount; 27 } 28 public void setLegCount(int legCount) { 29 this.legCount = legCount; 30 } 31 } 32 33 //雞類 34 public class Chicken extends Animal { 35 public void eat(){ 36 System.out.println(“雞正在吃東西”); 37 } 38 public void run(){ 39 System.out.println(“雞在跑"); 40 } 41 } 42 43 //鴨類 44 public class Duck extends Animal { 45 public void eat(){ 46 System.out.println(“鴨正在吃東西”); 47 } 48 public void run(){ 49 System.out.println(“鴨在跑"); 50 } 51 } 52 53 //測試類 54 55 public class Test { 56 public static void main(String[] args){ 57 Chicken chicken=new Chicken (); 58 chicken.eat(); 59 chicken.setType(“雞”); 60 chicken.setSkin(“金色"); 61 chicken.setLegCount(2); 62 System.out.println("動物品種是: "+chicken.getType()+", 膚色是: "+chicken.getSkin()+", 腿數"+t.getLegCount()); 63 chicken.run(); 64 Duck duck =new Duck (); 65 duck.eat(); 66 duck.fight(); 67 } 68 }
繼承執行的順序:
java中, new一個類的對象, 類里面的靜態代碼塊、 非靜態代碼塊、無參構造方法、 有參構造方法、 類的一般方法等部分, 它們的執行順序相對比較簡單, 例如:
1 public class FatherTest{ 2 private String name; 3 public FatherTest(){ 4 System.out.println(“--父類的無參數構造方法--”); 5 } 6 public FatherTest(String name){ 7 System.out.println(“--父類的有參數構造方法--”+this.name); 8 } 9 static{ 10 System.out.println(“--父類的靜態代碼塊--”); 11 } 12 { 13 System.out.println(“--父類的非靜態代碼塊--”); 14 } 15 public void speak(){ 16 System.out.println(“--父類的方法--”); 17 } 18 } 19 20 public static void main(String[] args){ 21 System.out.println(“--父類主程序--”); 22 FatherTest father = new FatherTest(“父親的名字”); 23 father.speak(); 24 } 25 26 執行結果為: 27 --父類的靜態代碼塊-- 28 --父類主程序-- 29 --父類的非靜態代碼塊-- 30 --父類的有參構造函數--父親的名字 31 --父類的方法-- 32 33 執行順序總結: 34 靜態代碼塊—>主程序—>非靜態代碼塊—>構造函數—>一般方法
加入子類繼承后的執行順序, 例如 :
1 public class SonTest extends FatherTest{ 2 private String name; 3 static{ 4 System.out.println("--子類的靜態代碼塊--"); } 5 { 6 System.out.println("--子類的非靜態代碼塊--"); 7 } 8 public SonTest(){ 9 System.out.println("--子類的無參構造方法--"); 10 } 11 public SonTest(String name){ 12 System.out.println("--子類的有參構造方法--"+name); 13 } 14 @Override 15 public void speak() { System.out.println("--子類重寫了父類的方法--"); } 16 } 17 18 19 public static void main(String[] args) { 20 System.out.println("--子類主程序--"); 21 FatherTest father=new FatherTest("父親的名字"); 22 father.speak(); 23 SonTest son=new SonTest("兒子的名字"); 24 son.speak(); 25 } 26 27 執行結果為: 28 --父類的靜態代碼塊-- 29 --子類的靜態代碼塊-- 30 --子類主程序-- 31 --父類的非靜態代碼塊-- 32 --父類的有參構造函數--父親的名字 33 --父類的方法-- 34 --父類的非靜態代碼塊-- 35 --父類的無參構造函數-- 36 --子類的非靜態代碼塊-- 37 --子類的有參構造方法--兒子的名字 38 --子類重寫了父類的方法--
方法的重寫:
方法重寫是在繼承關系下, 子類擁有與父類方法名、 參數(個數、順序、 類型)、 返回值類型完全相同, 訪問修飾符只能擴大或相等, 不可縮小, 但實現過程與父類不同的方法。 方法重寫也是多態的一種變現形式。
重寫必須滿足以下幾個條件:
在子類中可以根據需要對從基類中繼承來的方法進行重寫;
重寫的方法和被重寫的方法必須具有相同方法名稱、 參數列表和返回類型;
重寫方法不能使用比被重寫的方法更嚴格的訪問權限 ;
舉個栗子:
//雞類 class Chicken extends Animal { public void eat(){ System.out.println(“雞正在吃東西”);//對父類Animal中的eat方法進 行重寫 } public void run(){ System.out.println(“雞在跑");//可以添加新的方法 } }
Super關鍵字:
super關鍵字是一個特殊的變量, 它提供了對父類的方法。 可以用super主動調用父類的構造方法、 訪問父類中的成員。
super調用父類的構造方法:
public class Duck extends Animal { public Duck(String name){ super(name);//主動調用父類的構造方法 } }
super訪問父類的成員:
在子類方法中使用super訪問父類中隱藏的成員, 訪問形式是:
super.變量;
super.方法名(參數);
1 public class Duck extends Animal { 2 @Override 3 public void eat() { 4 System.out.println(); 5 } 6 public void quack(){ 7 System.out.println(super.name);//使用super調用父類的屬性 8 eat(); 9 super.eat();//使用super調用父類的eat()方法 10 } 11 public static void main(String[] args) { 12 new Duck().quack();//創建Duck類對象並調用quack方法 13 } 14 }
final 關鍵字:
“final”關鍵字用來修飾類、 方法和變量, 其含義“不可改變的、 最終的”。
1 修飾類 聲明為final的類不能派生子類,即此類不能被繼承; 2 public final class Person{ } 3 修飾變量 表示它為一個常量,變量一旦初始化,將不能改變; 4 final int COUNT = 5; 5 修飾方法 表示向編譯器表明子類不能重寫此方法; 6 public final void eat(){ }
多態(polymorphism)
在面向對象語言中, 多態性是指一個方法可以有多種實現版本,即“一種定義, 多種實現”。 利用多態可以設計和實現可擴展的系統, 只要新類也在繼承層次中。 新的類對程序的通用部分只需進行很少的修改, 或不做修改。 類的多態性表現為方法的多態性,方法的多態性主要有方法的重載和方法的覆蓋。
重載:
方法重載(overload)是指在同一個類中的多個方法可以同名但參數列表必須不同。 重載表現為同一個類中方法的多態性。
class Chicken { public void eat(){ System.out.println(“雞正在吃東西”); } public void eat(String food){ System.out.println(“雞在吃"+food);//重載eat方法 } }
方法重寫(override)是指子類沖定義了父類中同名的方法。 重寫表現為父子與子類之間方法的多態性。
//雞類 class Chicken extends Animal { public void eat(){ System.out.println(“雞正在吃東西”);//對父類Animal中的eat方法進 行重寫 } }
對象類型轉換:
基本類型的數據可以轉換類型, 當轉換類型較高時可以自動轉換, 當轉換類型較低時需要強制轉換。 對象類型也允許轉換, 這個轉換只限於java類層次結構圖上的一根枝干上, 即父類和子類之間。 枝干上離Object較近的為上, 相反較遠的為下, 由此對象的類型轉換分為“向上轉型”和“向下轉型”兩種。
1 public class Duck extends Animal { 2 @Override 3 public void eat() { 4 System.out.println(); 5 } 6 public void quack(){ 7 System.out.println("嘎嘎嘎"); 8 } 9 public static void main(String[] args) { 10 Animal a1 = new Animal();//實例化過程 11 Animal a2 = new Duck();//向上轉型 12 a1.eat(); 13 a2.eat(); 14 //a2.quack();//去除注釋會怎樣? 15 } 16 }
向下轉型:只能針對指向子類對象的基類對象引用進行 。
1 public class Duck extends Animal { 2 @Override 3 public void eat() { 4 System.out.println(); 5 } 6 public void quack(){ 7 System.out.println("嘎嘎嘎"); 8 } 9 public static void main(String[] args) { 10 Animal a = new Duck();//向上轉型 11 Duck b = (Duck) a;//向下轉型 12 a.eat(); 13 b.eat(); 14 b.quack(); 15 } 16 }
Instanceof 關鍵字 :
instanceof關鍵字是用來判斷其左邊對象是否為其右邊的實例, 返回boolean類型的數據 .
boolean result = Object instanceof class
同時, 也可以用來判斷繼承中的子類的實例是否為父類的實現。
..... public static void main(String[] args) { Animal a = new Duck();//向上轉型 if(a instanceof Duck){ ((Duck) a).quack(); } } .....