一.向上转型和向下转型
其实,无论是向上转型还是向下转型,两个类型之间必须有继承关系。
注意:
向上转型:自动类型转换
向下转型:强制类型转换,需要强制类型转换符
二.举例分析
public class Animal {
public void move() {
System.out.println("动物在移动");
}
}
public class Cat extends Animal{
public void move() {
System.out.println("猫儿在走猫步");
}
}
public class Bird extends Animal{
public void move() {
System.out.println("鸟儿在飞翔");
}
}
public class Test01 {
public static void main(String[] args) {
Animal a1 = new Animal();
a1.move();
Cat b1 = new Cat();
b1.move();
Bird c1 = new Bird();
c1.move();
Animal a2 = new Cat();
Animal a3 = new Bird();
a2.move();
a3.move();
}
}
大家注意看一下这两行代码:
Animal a2 = new Cat();
Animal a3 = new Bird();
在编译阶段,编译器只知道a2的类型是Animal,所以编译器在检查语法时,会去Animal.class字节码文件中寻找move方法,找到,绑定上move(),属于静态绑定。
在运行阶段,实际对象是堆中创建的对象Cat对象,所以在运行阶段会动态地去执行Cat对象的move方法。动态绑定。
(我们这里只分析了第一行代码,第二行类似)
这就是我们所说的多态,编译和运行不一样。
我们再总结一下多态是指:
- 父类型引用指向子类型对象
- 编译阶段:绑定父类型的方法
- 运行阶段:绑定子类型对象的方法
接下来我们改一下程序:
改一下cat类
public class Cat extends Animal{
public void move() {
System.out.println("猫儿在走猫步");
}
public void catchMouse() {
System.out.println("猫儿在抓老鼠");
}
}
改一下主类
public class Test01 {
public static void main(String[] args) {
Animal a1 = new Animal();
a1.move();
Cat b1 = new Cat();
b1.move();
Bird c1 = new Bird();
c1.move();
Animal a2 = new Cat();
Animal a3 = new Bird();
a2.move();
a3.move();
Animal a5 = new Cat();
a5.catchMouse();
}
}
我们使用cmd进行编译,但不运行,结果编译不通过
我们通过结果发现,编译的时候因为Animal.class无法找到catchMouse(),所以编译不通过。
所以我们要使用类型转换。
三.向下转型
什么时候必须使用向下转型呢?
—》当我们要使用子类中特有的方法时
我们按照这个思路,改一下主类:
public class Test01 {
public static void main(String[] args) {
Animal a1 = new Animal();
a1.move();
Cat b1 = new Cat();
b1.move();
Bird c1 = new Bird();
c1.move();
Animal a2 = new Cat();
Animal a3 = new Bird();
a2.move();
a3.move();
Animal a5 = new Cat();
//a5.catchMouse();
Cat x = (Cat)a5;
x.catchMouse();
}
}
我们强制转换了a5
结果正确。
四.instanceof判断
向下转型虽然解决了我们的问题,但是向下转型还是有风险的,我们在主类中加三行如下代码:
Animal a6 = new Bird();
Cat y = (Cat)a6;
y.catchMouse();
主类:
public class Test01 {
public static void main(String[] args) {
Animal a1 = new Animal();
a1.move();
Cat b1 = new Cat();
b1.move();
Bird c1 = new Bird();
c1.move();
Animal a2 = new Cat();
Animal a3 = new Bird();
a2.move();
a3.move();
Animal a5 = new Cat();
//a5.catchMouse();
Cat x = (Cat)a5;
x.catchMouse();
Animal a6 = new Bird();
Cat y = (Cat)a6;
y.catchMouse();
}
}
编译通过了,但运行没有通过。原因是运行阶段,实际对象Bird不能转换成Cat,它们之间没有继承关系,当然也就是鸟不可能抓老鼠,所以我们引进了instanceof判断避免这个异常。
大家要格外记住这个异常:java.lang.ClassCastException
类型转换异常
instanceof:(1)可以在运行阶段动态判断引用指向对象类型
(2)语法:(引用 instanceof 类型)
(3)instanceof的结果只能是true或者false
(4)c是一个引用,c中保存的内存地址指向堆内存中的对象。
假设(c instanceof Cat)为true表示c引用指向的堆内存中的java对象是一个Cat
假设(c instanceof Cat)为false表示c引用指向的堆内存中的java对象是一个Bird
我们加了判断条件后,代码如下:
public class Test01 {
public static void main(String[] args) {
Animal a1 = new Animal();
a1.move();
Cat b1 = new Cat();
b1.move();
Bird c1 = new Bird();
c1.move();
Animal a2 = new Cat();
Animal a3 = new Bird();
a2.move();
a3.move();
Animal a5 = new Cat();
//a5.catchMouse();
Cat x = (Cat)a5;
x.catchMouse();
Animal a6 = new Bird();
if(a6 instanceof Cat)
{
Cat y = (Cat)a6;
y.catchMouse();
}
}
}
运行结果正确。
最近笔者也在运营公众号,欢迎大家的关注!我们一起学习Java,一起进步。