什么是多態
定義:不同類的對象對同一個消息作出不同的響應。
解釋:見如下代碼
不同類的對象:子類cat和子類dog
同一個消息:調用eat()方法
不同的響應:分別為 cat eat 和 dog eat
//父類Animal
public class Animal { public void eat(){ System.out.println("animal eat"); } } //子類Cat public class Cat extends Animal{ @Override public void eat() { System.out.println("cat eat"); } } //子類Dog public class Dog extends Animal{ @Override public void eat() { System.out.println("dog eat"); } }
//測試
public class TestController {
public static void main(String[] args) {
Animal animal1 = new Cat();
Animal animal2 = new Dog();
animal1.eat();
animal2.eat();
}
}
結果:
cat eat
dog eat
由此引出多態存在的三個條件
多態存在的三個條件
1.有繼承關系
Cat和Dog繼承Animal
2.子類重寫父類的方法
Cat和Dog重寫父類Animal的eat方法
3.父類的引用變量指向子類對象
Animal animal1 = new Cat();
Animal animal2 = new Dog();
多態的作用
消除類型之間的耦合關系,即解耦。
舉例:
你定義了一個接口,功能是存儲文件。定義了一個下載工具類用來保存下載的文件。
//接口:存儲文件 public interface saveFile { void save(File file); } //下載工具類,有一方法為將下載的文件存儲下來(調用上述接口) public class DownLoadTools { saveFile saveFile; public void downLoad(File file){ saveFile.save(file); }
public void setDisk(saveFile saveFile){
this.saveFile = saveFile;
} }
別人寫了兩個實現類,分別將文件存儲在U盤和硬盤中。
//u盤存儲
public class UDisk implements saveFile{ @Override public void save(File file) { System.out.println("u盤存儲"); } }
//硬盤存儲 public class HardDisk implements saveFile{ @Override public void save(File file) { System.out.println("硬盤存儲"); } }
//測試 public class Test { public static void main(String[] args){ DownLoadTools downLoadTools = new DownLoadTools(); //文件存儲到U盤中 downLoadTools.setSaveFile(new UDisk()); downLoadTools.downLoad(new File("")); //文件存儲到硬盤中 downLoadTools.setSaveFile(new HardDisk()); downLoadTools.downLoad(new File("")); } }
結果:
u盤存儲
硬盤存儲
此時如果需要將下載文件存儲到CD中,只需要定義一個CDDisk實現類實現saveFile接口,無需更改downLoadTools下載工具類,這樣downLoadTools類就不依賴於任何具體的類,這樣就解除了與其他類之間的耦合性;
//CD存儲 public class CDDisk implements saveFile{ @Override public void save(File file) { System.out.println("CD存儲"); } } //測試 public class Test { public static void main(String[] args){ DownLoadTools downLoadTools = new DownLoadTools(); //文件存儲到U盤中 downLoadTools.setSaveFile(new UDisk()); downLoadTools.downLoad(new File("")); //文件存儲到硬盤中 downLoadTools.setSaveFile(new HardDisk()); downLoadTools.downLoad(new File("")); //文件存儲到CD中 downLoadTools.setSaveFile(new CDDisk()); downLoadTools.downLoad(new File("")); } }
結果:
u盤存儲
硬盤存儲
CD存儲
補充說明1:只要一個方法操作的是類而非接口,那么你只能使用這個類及其子類。如果你想要將這個方法應用於不在此繼承結構中的某個類,那么你就觸霉頭了。接口可以在很大程度上放寬這種限制(如上述的saveFile接口),因此,他使我們可以編寫可復用性更好的代碼。——引用《thinking in java》的某一些話。
補充說明2:簡單地說就是,沒有多態,那么等號左邊是啥右邊就得是啥,這就叫耦合,有了多態,左邊是父類(或者接口),右邊是子類(或實現類),我只管調用父類(或者接口)里面的方法就是了,至於你子類(實現類)怎么去實現,那是你的事,你要修改一下實現,你只管去把子類(實現類)換掉,我這邊一行代碼都不用變,這就解耦了。
多態用在什么地方?
1.用在方法的參數中
情景:一個人養了一只寵物,現在調用person的keepPet(參數1)方法需要知道是什么寵物在吃飯
參數1給的是父類Animal的話,那么無論你后來需要養Lion,Tiger,Panda等等,都可以直接繼承父類Animal,而Person的keepPet(參數1)方法不需要改變
若參數1給的是具體的Cat,Dog,Lion等等,那么你養了幾只寵物,就需要寫幾個keepPet()方法,如keepPet(Cat cat),keepPet(Dog dog),keepPet(Lion lion)等。
public class Person {
//參數給的是父類Animal,那么調用的時候傳參就可以是父類Animal的任意子類對象 public void keepPet(Animal animal){ animal.eat(); } } //父類Animal public class Animal { public void eat(){ System.out.println("animal eat"); } } //子類cat public class Cat extends Animal{ @Override public void eat() { System.out.println("cat eat"); } } //子類dog public class Dog extends Animal{ @Override public void eat() { System.out.println("dog eat"); } }
//測試
public class TestController {
public static void main(String[] args) {
Animal animal1 = new Cat();
Animal animal2 = new Dog();
Person person = new Person();
person.keepPet(animal1);
person.keepPet(animal2);
}
}
結果:
cat eat
dog eat
2.用在方法的返回類型中
前面的cat對象和dog對象都是直接new()的,現在設計一個工廠類,專門生產Animal
//以前
Animal animal1 = new Cat(); Animal animal2 = new Dog(); Person person = new Person(); person.keepPet(animal1); person.keepPet(animal2);
//現在
Animal animal1 = AnimalFactory.animalFactory("cat"); Animal animal2 = AnimalFactory.animalFactory("dog"); Person person = new Person(); person.keepPet(animal1); person.keepPet(animal2);
//工廠類方法,返回值類型是父類Animal,那么返回值就可以是Animal的所有的子類
public class AnimalFactory { public static Animal animalFactory(String animalName){ if(animalName.equals("cat")){ return new Cat(); }else if(animalName.equals("dog")){ return new Dog(); }else{ System.out.println("暫無該種動物"); return null; } } }
這實際上是設計模式中的工廠模式,當然如果類是一個完全獨立的類,無相似的類,那么直接new()就行了。