多态的理解
什么是多态
定义:不同类的对象对同一个消息作出不同的响应。
解释:见如下代码
不同类的对象:子类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 { public static void downLoad(File file,SaveFile saveFile){ saveFile.save(file); } }
写了两个实现类,分别将文件存储在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 static void main(String[] args) { File file = new File(""); SaveFile hardDisk = new HardDisk(); SaveFile uDisk = new UDisk(); DownLoadTools.downLoad(file,hardDisk); DownLoadTools.downLoad(file,uDisk); }
结果:
硬盘存储
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) { File file = new File(""); SaveFile hardDisk = new HardDisk(); SaveFile uDisk = new UDisk(); SaveFile cdDisk = new CdDISK(); DownLoadTools.downLoad(file,hardDisk); DownLoadTools.downLoad(file,uDisk); DownLoadTools.downLoad(file,cdDisk); } }
结果:
硬盘存储
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()就行了。