多态
多态概念
-
多态是指同一操作(方法eat())作用于某一对象(动物 🐕),可以有不同的解释,产生不同的执行结果。
-
多态存在的三个必要条件
- 需要存在继承和实现关系
- 同样的方法调用而执行不同操作、运行不同代码。(重写操作)
- 在运行时父类或者接口的引用变量可以引用其子类的对象
-
多态的作用
- 多态通过分离做什么和怎么做,从另一个角度将接口和实现进行分离
- “ 多态 ” 则消除了类型之间的耦合关系。
- 多态的存在提高了程序的可扩展性和后期的可维护性
public class AnimalDemo {
public static void main(String[] args) {
Animal dog = new Dog("旺财");
dog.eat();
Animal cat = new Cat("招财猫");
cat.eat();
}
}
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
// 这是一个通用的方法,通用的方法实现没有太大意义,
// 只是告诉其子类去实现它。
public void eat() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
// 对父类的方法进行重写
public void eat() {
System.out.println(getName() + "啃骨头");
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
// 对父类的方法进行重写
public void eat() {
System.out.println(getName() + "爱吃鱼");
}
}
对象上下转型
- 向上转型:由子类转型成父类,在继承图上是向上移动的,一般称为向上转型。
- 向上转型是一个较专用类型向较通用类型转换,所以总是安全的,也就是说,子类是父类的一个超集。
- 向上转型过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取方法。
- 与之相反的是向下转型,不安全(可能需要instanceOf操作符协助)
- LSP(liskov替换原则):子类型必须能够替换掉它们的基类型
- 安全的上转型和LSP的实施,充分体现继承的 “ is - a ” 关系。
public class AnimalDemo {
public static void main(String[] args) {
Animal dog = new Dog("旺财"); // 向上转型
// 向上转型是安全的,但可能会导致子类方法的丢失
// 父类的引用变量:只能调用父类中有的方法,或者是子类重写父类的方法
dog.eat();
// dog.sleep();
// 报错:The method sleep() is undefined for the type Animal
Animal cat = new Cat("招财猫");
cat.eat();
// 向下转型是不安全的
// Cat cat2 = (Cat) dog; // java.lang.ClassCastException
Cat cat1 = (Cat) cat;
cat1.eat();
}
}
class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
// 这是一个通用的方法,通用的方法实现没有太大意义,
// 只是告诉其子类去实现它。
public void eat() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
// 对父类的方法进行重写
public void eat() {
System.out.println(getName() + "啃骨头");
}
public void sleep() {
System.out.println(getName() + "要睡觉");
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
// 对父类的方法进行重写
public void eat() {
System.out.println(getName() + "爱吃鱼");
}
}
- instanceOf运算符用来在运行时,通过返回一个布尔值来指出对象是否是特定类或者是它的子类的一个实例
- 用法:
result = object instanceOf class
result:布尔类型
object:必选项,任意对象表达式
class:必选项,任意已定义的对象类
说明:如果object是class或其子类的一个实例,则instanceOf运算符返回true,如果不是,或者object是null,则返回false。 - 典型使用场合
在对对象做下转型之前,没有其他有关对象类型信息时务必使用instanceOf来判断一下,以避免抛出ClassCastException异常。
动态绑定与静态绑定
- 静态绑定和动态绑定的概念:
- 在程序执行前方法已经被绑定,针对Java简单的可以理解为程序编译期的绑定(静态绑定),java当中的方法是final,static,private和构造方法都是前期绑定的。
- 运行时,根据变量实际引用的对象类型决定调用哪个方法(动态绑定)
- 静态绑定在编译期进行:
- Person.sayHi();
- 动态绑定在运行期进行:
- Person p = new Teacher();
- p.sayHi();
- 多态的概念基于对象引用的动态绑定特性
多态应用
- 简单来说,多态是具有表现多种行为能力的特征。
- 同一个实现接口,使用不同的实例而执行不同操作。
public class PrinterDemo{
public static void main(String[] args){
ColorPrinter cp = new ColorPrinter("惠普");
School school = new School();
school.setColorPrinter(cp);
school.print("hello java");
BlackPrinter bp = new BlackPrinter("戴尔");
school.setBlackPrinter(cp);
school.print("hello java");
}
}
class Printer{
private String brand;
public Printer(String brand){
this.brand = brand;
}
//打印的方法应该由其子类来具体实现。
public void print(String content){
}
public String getBrand(){
return brand;
}
}
class School{
private ColorPrinter cp = null;
private BlackPrinter bp = null;
//安装彩色打印机
public void setColorPrinter(ColorPrinter cp){
this.cp = cp;
}
//安装黑白打印机
public void setBlackPrinter(BlackPrinter bp){
this.bp = bp;
}
public void print(String content){
//交给中心所安装的彩色打印机来打印
cp.print(content);
}
}
class ColorPrinter extends Printer{
public ColorPrinter(String brand){
super(brand);
}
//对父类的方法进行重写
public void print(String content){
System.out.println(getBrand() + "彩色打印:" + content);
}
}
class BlackPrinter extends Printer{
public BlackPrinter(String brand){
super(brand);
}
//对父类的方法进行重写
public void print(String content){
System.out.println(getBrand() + "黑白打印:" + content);
}
}