Java基礎之面向物件
面向物件的三大特性:封裝性、繼承性、多型性
1.方法就是一種封裝
2.關鍵字private也是一種封裝
封裝就是將一些細節資訊隱藏起來,對於外界不可見
package com.dcits.day05.demo03; public class Demo02Method { public static void main(String[] args) { int[] array = {5,15,25,35,111}; int max = getMax(array); System.out.println(max); }public static int getMax(int[] array) { int max = array[0]; for (int i = 0; i < array.length; i++) { if (array[i] > max) { max = array[i]; } } return max; } }
private關鍵字的作用以及使用
一旦使用了private進行修飾,那麼本類中可以隨意訪問,但是超出了本類的範圍就不能再訪問了
可以通過間接訪問的方式,自定義一對兒Getter/Setter方法,必須叫 setXxx 或者是 getXxx
對於Getter來說,不能有引數,返回值型別和成員變數對應
對於Setter來說,不能有返回值,引數型別和成員變數對應
// Person類 package com.dcits.day05.demo03; public class Person { String name; private int age; public void show() { System.out.println("我叫:" + name +",今年" + age); }public void setAge(int num) { if (num < 100 && num >=9) { age = num; } else { age = 0; System.out.println("資料不合理"); } } public int getAge() { return age; } } // 呼叫 package com.dcits.day05.demo03; public class Demo03Person { public static void main(String[] args) { Person person = new Person(); person.name = "趙麗穎"; // person.age = 18; 當成員變數被private修飾的時候,外部無法訪問,只能通過間接的方式Setter,Getter person.setAge(-20); person.show(); } }
布林型別的特殊情況
// 類 package com.dcits.day05.demo03; public class Student { private String name; private int age; private boolean male; public void setMale(boolean b){ male = b; } public boolean isMale() { return male; } public void setName(String str){ name = str; } public String getName() { return name; } public void setAge(int num) { age = num; } public int getAge() { return age; } } // 呼叫 package com.dcits.day05.demo03; public class Demo04Student { public static void main(String[] args) { Student stu = new Student(); stu.setName("alex"); stu.setAge(10); stu.setMale(true); System.out.println(stu.getName()); System.out.println(stu.getAge()); System.out.println(stu.isMale()); } }
this關鍵字的使用
當方法的區域性變數和類的成員變數重名的時候,根據就近原則,優先使用區域性變數,如果需要訪問 本類當中的成員變數,需要使用格式:this.成員變數
通過誰呼叫的方法,誰就是this
// 類 package com.dcits.day05.demo04; public class Person { String name; public void sayHi(String name) { System.out.println(this.name + "你好,我是" + name); } } // 呼叫 package com.dcits.day05.demo04; public class Demo01Person { public static void main(String[] args) { Person person = new Person(); person.name = "6666"; person.sayHi("777"); } }
構造方法
構造方法是專門用來建立物件的方法,當我們使用關鍵字new來建立物件的時候,其實就是在呼叫構造方法
注意事項:
-
構造方法的名稱必須和所在的類名稱完全一樣,就連大小寫也要完全一樣
-
構造方法不要寫返回值型別,連void都不要寫
-
構造方法不能return一個具體的返回值
-
如果沒有編寫任何構造方法,那麼編譯器預設會贈送一個構造方法,沒有引數、方法體什麼都不做
-
一旦編寫了一個構造方法,那麼編譯器就不再贈送
-
構造 方法也是可以過載的
// 類 package com.dcits.day05.demo04; public class Student { private String name; private int age; public Student(String name,int age) { this.name = name; this.age = age; System.out.println("有引數的構造方法!!"); } public Student() { System.out.println("無引數的構造方法執行啦!!"); } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setAge(int age) { this.age = age; } public int getAge() { return age; } } // 呼叫 package com.dcits.day05.demo04; public class Demo02Student { public static void main(String[] args) { Student stu = new Student(); Student stu1 = new Student("aaa",20); stu1.setAge(23); System.out.println(stu1.getAge()); System.out.println(stu1.getName()); } }
區域性變數和成員變數
-
定義的位置不一樣
-
區域性變數:在方法的內部
-
成員變數:在方法的外部,直接寫在類當中
-
-
作用範圍不一樣
-
區域性變數:只有方法 才可以使用,出了方法就不能再使用了
-
成員變數:整個類都可以通用
-
-
預設值不一樣
-
區域性變數:沒有預設值,如果想要用,必須手動賦值
-
成員變數:如果沒有賦值,會有預設值,規則和陣列一樣
-
-
記憶體的位置不一樣
-
區域性變數:位於棧記憶體
-
成員變數:位於堆記憶體
-
-
生命週期不一樣
-
區域性變數:隨著方法進棧而誕生,隨著方法出棧而消失
-
成員變數:隨著物件建立而誕生,隨著物件被垃圾回收而消失
-
標準類的組成部分
一個標準的類通常擁有下面的四個部分:
-
所有的成員變數都要使用private關鍵字來修飾
-
為每一個成員變數編寫一對Getter、Setter方法
-
編寫一個無引數的構造方法
-
編寫一個全引數的構造方法
繼承
繼承是多型的前提,如果沒有整合,就沒有多型
繼承解決的主要問題就是:共性抽取
定義類時的兩個注意事項:
-
成員變數時直接定義在類當中的,在方法外面
-
成員方法不要寫static關鍵字
繼承的格式:
// 父類 package com.dcits.day08.demo01; public class Employee { public void method() { System.out.println("父類執行!"); } } // Teacher子類 package com.dcits.day08.demo01 public class Teacher extends Employee{ } // Assistant子類 package com.dcits.day08.demo01; public class Assistant extends Employee { } // 呼叫 package com.dcits.day08.demo01; public class Demo01Extends { public static void main(String[] args) { Teacher teacher = new Teacher(); Assistant assistant = new Assistant(); teacher.method(); assistant.method(); } }
在父子類的繼承關係當中,如果成員變數重名,則建立子類時,訪問有兩種方式:
-
直接通過子類物件訪問成員變數
-
等號左邊是誰,就優先使用誰,沒有則向上找
-
-
間接通過成員方法訪問成員變數
-
該方法屬於誰,就優先用誰,沒有則向上找
-
// 父類 package com.dcits.day08.demo02; public class Fu { int numFu = 10; int num = 100; public void methodFu() { System.out.println(num); } } // 子類 package com.dcits.day08.demo02; public class Zi extends Fu { int numZi = 20; int num = 200; public void methodZi() { System.out.println(num); } } // 呼叫 package com.dcits.day08.demo02; public class Demo01ExtendsField { public static void main(String[] args) { Fu fu = new Fu(); System.out.println(fu.numFu); Zi zi = new Zi(); System.out.println(zi.numFu); System.out.println(zi.numZi); // 當父類與子類的成員變數重名的時候 System.out.println(zi.num); // System.out.println(zi.abc); // zi.methodZi(); zi.methodFu(); } }
區分子類方法中的三種重名變數
-
直接使用的方法中的變數
-
this.變數名:呼叫本類中的成員變數
-
super.變數名:呼叫父類中的成員變數
// 父類 package com.dcits.day08.demo03; public class Fu { int num = 10; } // 子類 package com.dcits.day08.demo03; public class Zi extends Fu { int num = 20; public void method() { int num = 30; System.out.println(num); // 30 區域性變數 System.out.println(this.num); // 20 本類的成員變數 System.out.println(super.num); // 10 父類的成員變數 } } // 呼叫 package com.dcits.day08.demo03; public class Demo01ExtendsField { public static void main(String[] args) { Zi zi = new Zi(); zi.method(); } }
繼承中成員方法的訪問特點
在父子類的繼承關係當中,建立子類物件,訪問成員方法的規則:建立的物件是誰,就優先使用誰,如果沒有則向上找
注意:無論是成員方法還是成員變數,如果沒有都是向上找父類u,絕不會向下找子類
// 父類 package com.dcits.day08.demo04; public class Fu { public void methodFu() { System.out.println("父類中的方法執行啦!"); } public void method() { System.out.println("父類重名執行啦!"); } } // 子類 package com.dcits.day08.demo04; public class Zi extends Fu { public void methodZi() { System.out.println("子類中的方法執行啦!"); } public void method() { System.out.println("子類重名執行啦!"); } } // 呼叫 package com.dcits.day08.demo04; public class Zi extends Fu { public void methodZi() { System.out.println("子類中的方法執行啦!"); } public void method() { System.out.println("子類重名執行啦!"); } }
繼承方法中的覆蓋重寫
重寫:方法的名稱一樣,引數列表也一樣,覆蓋、覆寫
過載:方法的名稱一樣,引數列表不一樣
方法的覆蓋重寫特點:建立的是子類物件,則優先用子類方法
方法覆蓋重寫的注意事項:
-
必須保證父子類之間的方法名稱相同、引數列表也相同
-
@Override:寫在方法前面,用來檢測是不是有效的正確覆蓋重寫,這個註釋就算不寫,只要滿足要求,也是正確的覆蓋重寫
-
子類方法的返回值必須小於等於父類方法的返回值範圍。Object類是所有類的父類
-
子類方法的許可權必須大於等於父類方法的許可權修飾符。public > protected > (default) > private 注意:(default)不是關鍵字default,而是什麼都不寫,留空
繼承中方法的覆蓋重寫應用場景
// 父類 package com.dcits.day08.demo06; // 本來的老款手機 public class Phone { public void call() { System.out.println("打電話"); } public void send() { System.out.println("發簡訊"); } public void show() { System.out.println("顯示號碼"); } } // 子類 package com.dcits.day08.demo06; // 上市的新款手機 public class NewPhone extends Phone { @Override public void show() { // System.out.println("顯示號碼"); super.show(); System.out.println("顯示姓名"); System.out.println("顯示頭像"); } } // 呼叫 package com.dcits.day08.demo06; public class Demo01Phone { public static void main(String[] args) { Phone phone = new Phone(); phone.call(); phone.send(); phone.show(); System.out.println("==========="); NewPhone newPhone = new NewPhone(); newPhone.call(); newPhone.send(); newPhone.show(); } }
繼承中構造方法的訪問特點
-
子類構造方法當中有一個預設隱含的 "super()" 呼叫,所以一定是先呼叫的父類構造,後執行的子類構造
-
子類構造可以通過super關鍵字來呼叫父類過載構造
-
super的父類構造呼叫,只能是第一個語句 ,不能一個子類構造呼叫多次super構造
-
子類必須呼叫父類構造方法,不寫贈送super() 寫了則用寫的指定該的super呼叫,super只能有一個,還必須是第一個
super關鍵字的用法(訪問父類的內容):
-
在子類的成員方法中,訪問父類的成員變數
-
在子類的成員方法中,訪問父類的成員方法
-
在子類的構造方法中,訪問父類的構造方法
// 父類 package com.dcits.day08.demo08; public class Fu { int num = 10; public void method(){ System.out.println("父類方法"); } } // 子類 package com.dcits.day08.demo08; public class Zi extends Fu { int num = 20; public Zi(){ super(); } public void methodZi() { System.out.println(super.num); // 父類的num } public void method(){ super.method(); System.out.println("子類方法"); } }
this關鍵字的三種使用方法(訪問本類的內容)
-
在本類的成員方法中,訪問本類的成員變數
-
在本類的成員方法中訪問本類的另一個成員方法
-
在本類的構造方法中,訪問本類的另一個構造方法
注意:
-
在第三種用法中要注意:this(..)呼叫必須是構造方法的一個語句,唯一一個
-
super和this兩種構造呼叫,不能同時使用
// 父類 package com.dcits.day08.demo09; public class Fu { int num = 30; } // 子類 package com.dcits.day08.demo09; public class Zi extends Fu { int num = 20; public Zi(){ this(123); // 本類的無參構造,呼叫本類的有參構造 // this(1,2) } public Zi(int n){ } public Zi(int n,int m){ } public void showNum(){ int num = 10; System.out.println(num); System.out.println(this.num); // 本類中的成員變數 System.out.println(super.num); // 父類中的 成員變數 } public void methodA() { System.out.println("AAA"); } public void methodB() { methodA(); this.methodA(); System.out.println("BBB"); } }
this、super的關鍵字圖解
Java語言繼承的三個特點:
-
一個類的 直接父類只能有唯一一個
-
Java語言可以多繼承
-
一個子類的直接父類是唯一的,但是一個父類可以擁有很多個子類
多型
多型的定義以及基本使用
extends繼承或者implements實現,是多型的前提。
小明這個物件既有學生形態,也有人類形態。一個物件擁有多種形態,這就是:物件的多型性
程式碼當中體現多型性,其實就是一句話:父類引用指向子類物件
格式:
-
父類名稱 物件名 = new 子類名稱()
-
介面名稱 物件名 = new 實現類名稱()
// 父類 package com.dcits.day09.demo04; public class Fu { public void method(){ System.out.println("父類方法"); } public void methodFu(){ System.out.println("父類特有方法"); } } // 子類 package com.dcits.day09.demo04; public class Zi extends Fu { @Override public void method() { System.out.println("子類方法"); } } // 呼叫 package com.dcits.day09.demo04; public class Demo01Multi { public static void main(String[] args) { // 使用多型的寫法 // 左側父類的引用指向右側子類的物件 Fu obj = new Zi(); // new 的是誰就呼叫誰 的方法 obj.method(); // 子類方法 obj.methodFu(); // 父類特有方法 } }
多型中成員變數的使用特點
訪問成員變數的兩種方式:
-
直接通過物件名稱訪問成員變數,看等號左邊是誰,優先用誰,沒有則向上找
-
間接通過成員方法訪問成員變數,看該方法屬於誰,優先用誰,沒有則像上找
// 父類 package com.dcits.day09.demo05; public class Fu { int num = 10; public void showNum(){ System.out.println(num); } } // 子類 package com.dcits.day09.demo05; public class Zi extends Fu { int num = 20; int age = 16; @Override public void showNum() { System.out.println(num); } } // 呼叫 package com.dcits.day09.demo05; public class Demo01MultiField { public static void main(String[] args) { Fu obj = new Zi(); System.out.println(obj.num); // 父類中的10 System.out.println("====================="); obj.showNum(); // 子類沒有覆蓋重寫,就是父類中的num,一旦子類重寫後就是子類中的num } }
多型中成員方法的使用特點
在多型的程式碼當中,成員方法的優先訪問規則是:看new的是誰,就優先用誰,沒有則向上找
注意:編譯看左邊,執行看右邊
對比一下:
-
成員變數:編譯看左邊,執行還看左邊
-
成員方法:編譯看左邊,執行看右邊
// 父類 package com.dcits.day09.demo05; public class Fu { int num = 10; public void showNum(){ System.out.println(num); } public void method(){ System.out.println("父類方法"); } public void methodFu(){ System.out.println("父類特有方法"); } } // 子類 package com.dcits.day09.demo05; public class Zi extends Fu { int num = 20; int age = 16; @Override public void showNum() { System.out.println(num); } @Override public void method() { System.out.println("子類方法"); } public void methodZi(){ System.out.println("子類特有方法"); } } // 呼叫 package com.dcits.day09.demo05; public class Demo01MultiField { public static void main(String[] args) { Fu obj = new Zi(); obj.method(); // 父子都有,優先使用子類 obj.methodFu(); // 子類沒有,父類有,向上找到父類 // 編譯看左,左邊是Fu,沒有methodZi方法,所以編譯報錯 // obj.methodZi(); // 錯誤寫法 // System.out.println(obj.num); // 父類中的10 // System.out.println("====================="); // obj.showNum(); // 子類沒有覆蓋重寫,就是父類中的num,一旦子類重寫後就是子類中的num } }
使用多型的好處
物件的向上轉型
物件的向上轉型,其實就是多型寫法
格式: 父類名稱 物件名 = new 子類名稱()
含義:右側建立一個子類物件,把它當作父類來看待使用
注意事項:
-
向上轉型一定是安全的,從小範圍轉到了大範圍
-
但是有一個弊端:物件一旦向上轉型為父類,那麼就無法呼叫子類原本的特有內容
類似於:double num = 100 正確 int----double 自動型別轉換
// 父類 package com.dcits.day09.demo06; public abstract class Animal { public abstract void eat(); } // 子類 package com.dcits.day09.demo06; public class Cat extends Animal { @Override public void eat() { System.out.println("貓吃魚。。。"); } } // 呼叫 package com.dcits.day09.demo06; public class Demo01Main { public static void main(String[] args) { Animal animal = new Cat(); animal.eat(); } }
物件的向下轉型
物件的向下轉型,其實是一個還原動作
格式:子類名稱 物件名 = (子類名稱) 父類物件
含義:將父類物件,還原成為原本的子類物件
注意事項:
-
必須保證物件本來建立的時候,就是貓,才能向下轉型成為貓
-
如果物件建立的時候本來不是貓,現在非要向下轉型成為貓,就會報錯
類似於:int num = (int) 10.0 正確 int num = (int) 10.5 錯誤,發生精度損失
// 父類 package com.dcits.day09.demo06; public abstract class Animal { public abstract void eat(); } // 貓子類 package com.dcits.day09.demo06; public class Cat extends Animal { @Override public void eat() { System.out.println("貓吃魚。。。"); } public void catchMouse() { System.out.println("貓抓老鼠!!"); } } // 狗子類 package com.dcits.day09.demo06; public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃shit"); } public void watchMouse() { System.out.println("狗看家!!"); } } // 呼叫 package com.dcits.day09.demo06; public class Demo01Main { public static void main(String[] args) { Animal animal = new Cat(); // 物件的向上轉型 animal.eat(); // 向下轉型 Cat cat = (Cat) animal; cat.catchMouse(); // 貓抓老鼠!! // 下面是錯誤的向下轉型 // 本來new的時候是一隻貓,現在非要轉成狗 // java.lang.ClassCastException Dog dog = (Dog) animal; // 錯誤寫法 } }
用instanceof 關鍵字進行型別判斷
package com.dcits.day09.demo06; public class Demo01Instanceof { public static void main(String[] args) { Animal animal = new Cat(); // 本來是一隻貓 animal.eat(); // 如果需要呼叫子類特有的方法,需要向下轉型 if (animal instanceof Dog){ Dog dog = (Dog) animal; dog.watchMouse(); } if (animal instanceof Cat){ Cat cat = (Cat) animal; cat.catchMouse(); } giveMeAPet(new Dog()); // 在你呼叫這個方法的時候,方法本身不知道傳遞過來的是哪個類,所以需要進行判斷 } public static void giveMeAPet(Animal animal){ if (animal instanceof Dog){ Dog dog = (Dog) animal; dog.watchMouse(); } if (animal instanceof Cat){ Cat cat = (Cat) animal; cat.catchMouse(); } } }
介面多型的綜合案例
// USB介面類:兩個抽象方法:開啟USB、關閉USB package com.dcits.day09.demo07; public interface USB { public abstract void open(); public abstract void close(); } // 電腦類:開機、關機、連線USB介面並對USB裝置進行對應操作 package com.dcits.day09.demo07; public class Computer { public void powerOn(){ System.out.println("膝上型電腦開機"); } public void powerOff(){ System.out.println("膝上型電腦關機"); } // 使用USB裝置的方法,使用介面作為方法的引數 public void useDevice(USB usb) { usb.open(); // 判斷當前類是屬於哪個類之後,在獲取類中的特有方法 if (usb instanceof Mouse){ Mouse mouse = (Mouse) usb; mouse.click(); } else if (usb instanceof KeyBoard){ KeyBoard keyboard = (KeyBoard) usb; keyboard.type(); } usb.close(); } } // 滑鼠類:重寫介面類中的開啟、關閉功能,並實現自己的獨有功能 package com.dcits.day09.demo07; public class Mouse implements USB { @Override public void open() { System.out.println("開啟滑鼠"); } @Override public void close() { System.out.println("關閉滑鼠"); } public void click(){ System.out.println("點選滑鼠!"); } } // 鍵盤類:重寫介面類中的開啟、關閉功能,並實現自己的獨有功能 package com.dcits.day09.demo07; public class KeyBoard implements USB { @Override public void open() { System.out.println("開啟鍵盤"); } @Override public void close() { System.out.println("關閉鍵盤"); } public void type(){ System.out.println("敲鍵盤!"); } }