初始理解
其實這些知識很早就有接觸,而且一些概念也牢記於心了。自己敘述面向對象的特徵會是這樣的:
面向對象的三大特徵是封裝、繼承和多態。封裝是對代碼的封裝以實現迪內聚高耦合的設計,使代碼更安全且具有良好的擴展性。繼承是父類產生子類的過程,子類可以使用父類的非私有的屬性和方法。多態是一個對象在不同時刻可以表現出不同狀態的現象。外加Animal和Cat的例子。
這一段時間敲了不少的Java代碼,在敲代碼的過程中想了無數次的面向對象這幾個概念,對他們有了更深的瞭解,在這裏分享一下。
封裝
封裝確實是對代碼的封裝,但是隻是這樣理解卻又太膚淺了,至少結合Java來思考一下里面的封裝嘛。
不知道大家有沒有想過我們在寫JavaBean的時候爲什麼要將屬性的權限修飾爲private,其實是爲了使我們的代碼更安全。分析如下:
public class Cat {
//這裏通過private修飾屬性,外界訪問屬性需要通過getter和setter方法
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
//假設我們設置age,如果用戶惡意將age設置爲100
//衆所周知,impossible,因此我們可以通過setter方法進行if判斷然後再賦值
public void setAge(int age) {
this.age = age;
}
}
我們可以考慮一下如果沒有setter方法的判斷,我們將該類的屬性設置爲public呢?那麼用戶的惡意輸入,怎樣規避呢?
總之:private是封裝的一種體現。
封裝還有其他的方法:爲了提高代碼的複用性可以將公共邏輯抽取成方法,將公共屬性抽取成類。例如我們在不同的位置用到了相同的for循環,在idea中我們就可以選中相同的for循環部分,點擊快捷鍵 ctrl + alt + m 將其抽取爲方法。
繼承
繼承是面向對象的三大特徵之一,過程就是使子類獲得父類的屬性和方法。
這個過程較容易理解,關鍵字是extends,如果我們定義的類沒有顯式繼承某個類,系統默認爲我們繼承Objects。繼承是我們代碼的coding量變少了,提高了代碼的複用性。
這裏更深的體會是繼承提高了代碼的維護性。主要表現就是如果方法的代碼需要修改,某些情況下我們只需要修改一處就可以實現。
但是這裏還有一點沒有想通的繼承肯定會增加代碼的耦合性,我們爲什麼還要這樣誇大繼承呢?我有這種疑問就是陷入了一個思維的誤區,可以看這篇文章來解疑:爲耦合辯護,爲繼承伸冤
多態
多態的三個必要條件是:
- 有繼承或實現關係
- 有方法的重寫
- 父類引用指向子類對象
class Fu {
int num = 10;
public void method(){
System.out.println("Fu.. method");
}
}
class Zi extends Fu {
int num = 20;
public void method(){
System.out.println("Zi.. method");
}
}
public class Test2Polymorpic {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.num);
f.method();
}
}
關於爲什麼訪問成員變量和成員方法的會分別get父類和子類的值和方法,這裏有講解。從虛擬機角度看Java多態->(重寫override)的實現原理
- 好處:提高程序的擴展性。定義方法時候,使用父類型作爲參數,在使用的時候,使用具體的子類型參與操作
- 弊端:不能使用子類的特有成員
解決弊端可以通過向下轉型:格式爲子類型 對象名 = (子類型)父類引用;
class Fu {
public void show(){
System.out.println("Fu..show...");
}
}
class Zi extends Fu {
@Override
public void show() {
System.out.println("Zi..show...");
}
public void method(){
System.out.println("我是子類特有的方法, method");
}
}
public class Test {
public static void main(String[] args) {
//向上轉型 : 父類引用指向子類對象
Fu f = new Zi();
f.show();
// 多態的弊端: 不能調用子類特有的成員
// f.method();
//解決方法:
// A: 直接創建子類對象
// B: 向下轉型
//向下轉型 : 從父類類型, 轉換回子類類型
Zi z = (Zi) f;
z.method();
}
}
如果被轉的引用類型變量,對應的實際類型和目標類型不是同一種類型,那麼在轉換的時候就會出現ClassCastException,可以使用instanceOf來解決。
abstract class Animal {
public abstract void eat();
}
class Dog extends Animal {
public void eat() {
System.out.println("狗喫肉");
}
public void watchHome(){
System.out.println("看家");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("貓喫魚");
}
}
public class Test4Polymorpic {
public static void main(String[] args) {
useAnimal(new Dog());
useAnimal(new Cat());
}
public static void useAnimal(Animal a){
a.eat();
// 判斷a變量記錄的類型, 是否是Dog
if(a instanceof Dog){
Dog dog = (Dog) a;
dog.watchHome();
}
}
}
最後再來一張圖體會一下多態的強大:::::