- 由子类转型成父类,在继承图上是向上移动的,一般称为向上转型
- 向上转型是从一个专用类型向通用类型转换,所以总是安全的,也就是说,子类是父类的一个超集
- 向上转型过程中,类接口中唯一可能发生的事情就是丢失方法,而不是获取方法
- 与之相反的操作是向下转型,不安全(可能需要instanceof操作符协助)
- 里氏替换原则:子类型必须能够替换掉他们的父类型
- 安全的上转型和LSP的实施,充分体现继承的“is-a”的关系
public class AnimalDemo {
public static void main(String[] args) {
/**
* 向上转型可能是安全的,但是有可能导致子类方法的丢失,子类中特有的方法有可能不能调用
* 父类中的引用只能调用父类中有的方法或子类重写父类的方法
*/
Animal dog = new Dog("旺财");//向上转型
dog.eat();
//dog.sleep();//父类没有这个方法,子类中特有方法调用报错
Animal cat = new Cat("招财猫");
cat.eat();
//向下转型是不安全的,需用instanceof判断
if (dog instanceof Cat) {
//没有打印,这种情况下存在异常
System.out.println("aa");
Cat cat2 = (Cat) dog;
}
//转化类型一直,从专有类型转换为通用类型,可以调用子类特有方法
if (cat instanceof Cat) {
System.out.println("aa");
Cat cat2 = (Cat) cat;
cat2.sleep();
}
}
}
class Animal{
@SuppressWarnings("unused")
private String name;
public Animal(String name) {
this.name = name;
}
//这是一个通用的方法,告诉其子类去实现
public void eat() {
}
}
class Dog extends Animal{
public Dog(String name) {
super(name);
}
//对父类方法重写
public void eat() {
System.out.println("坑骨头");
}
public void sleep() {
System.out.println("睡觉");
}
}
class Cat extends Animal{
public Cat(String name) {
super(name);
}
public void eat() {
System.out.println("吃鱼肉");
}
public void sleep() {
System.out.println("睡觉");
}
}
程序输出
坑骨头
吃鱼肉
aa
睡觉
动态绑定和静态绑定
静态绑定
在程序执行前方法已经被绑定,针对java简单的可以理解为程序编译期的绑定(静态绑定)Java当中的方法final,static,private和构造方法都是前期绑定的
通俗来讲,程序在执行时,它的类型是不能够改写的,final,static,private和构造方法是不能改写的
动态绑定
运行时,根据变量实际引用的对象类型决定调用哪个方法(动态绑定)
静态绑定在编译器进行
Person sayHi() 编译时就已经确定sayHi() 方法是Person的,此方法类型为上述三种类型
动态绑定在运行期进行
Person p = new Teacher();
p.sayHi();
多态的概念是基于对象引用的动态绑定特性
- 多态是具有表现多种行为能力的特征
- 同一个实现接口,使用不同的实例而执行不同的操作,如上述程序中的猫狗操作,以及下图帮助理解
public class PrinterDemo {
public static void main(String[] args) {
ColorPrinter colorPrinter = new ColorPrinter("惠普打印机");
School school = new School();
/* school.setColorPrinter(colorPrinter);
school.print("hello");*/
BlankPrinter blankPrinter = new BlankPrinter("戴尔");
school.setBlankPrinter(blankPrinter);
blankPrinter.print("java");
}
}
class Priter{
private String brand;
public Priter(String brand) {
super();
this.brand = brand;
}
public String getBrand() {
return brand;
}
//打印的方法应该由其子类来具体的实现
public void print(String content) {
}
}
class ColorPrinter extends Priter{
public ColorPrinter(String brand) {
super(brand);
}
//对父类的方法重写
public void print(String content) {
System.out.println(getBrand() + "彩色打印" + content);
}
}
class BlankPrinter extends Priter{
public BlankPrinter(String brand) {
super(brand);
}
//对父类的方法重写
public void print(String content) {
System.out.println(getBrand() + "黑白打印" + content);
}
}
/**
* 通过学校类组合打印机两个类
* @author QuLvT
*
*/
class School{
private ColorPrinter cp = null;
private BlankPrinter bp = null;
//安装打印机的方法
public void setColorPrinter(ColorPrinter cp) {
this.cp = cp;
}
public void setBlankPrinter(BlankPrinter bp) {
this.bp = bp;
}
//交给学校安装的哪种类型的打印机来打印
public void print(String content) {
//彩色
//cp.print(content);
//黑白
bp.print(content);
}
}
关于多态的理解,可以好好理解一些这个程序
开闭原则:对修改时封闭的,对扩展时开放的,不要违反开闭原则
可以使用多态解决这个问题,父类的引用对象可以引用其子类的对象