java的多态性和向下转型
文章内容选自尚硅谷,采用的java8环境
java对象引用的详解
有关java多态性的详解,可以见上一个博客 java的多态性.
package com.atguigu.java4;
public class Person {
String name;
int age;
int id = 1001;
public void eat(){
System.out.println("人吃饭");
}
public void walk(){
System.out.println("人走路");
}
}
package com.atguigu.java4;
public class Man extends Person {
boolean isSmoking;
int id = 1002;
public void earnMoney(){
System.out.println("男人挣钱");
}
public void eat(){
System.out.println("男人吃饭");
}
public void walk(){
System.out.println("男人走路");
}
}
package com.atguigu.java4;
public class Woman extends Person {
boolean isBeauty;
public void eat(){
System.out.println("女人吃饭");
}
public void walk(){
System.out.println("女人走路");
}
public void goShopping(){
System.out.println("女人爱逛街");
}
}
当执行代码
Person p2 = new Man();
java多态性中对象属性的内存解析的时候,有如图
虽然p2指向一个Man对象的堆空间地址,但是并不能让p2调用子类特有的属性
// p2.isSmoking = True;
这样写编译器会报错,虽然通过分析,p2指向的堆空间对象是包含isSmoking这个属性的,但是这个对象毕竟是Man对象,不能够进行属性的引用,换言之,p2只能调用其声明类型的方法和属性。
父类的引用调用子类的属性(向下转型)
但如果想让父类的引用(p2)调用子类的属性(isSmoking)也是有方法的,就是采用强制类型转换。
package com.atguigu.java4;
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Man();
p2.eat();
System.out.println(p2.id);
// p2.isSmoking = True;
Man m1 = (Man)p2;
m1.isSmoking = true;
m1.earnMoney();
System.out.println(m1.isSmoking);
}
}
采用这种方法就可以进行对子类属性的调用了,运行结果为
男人吃饭
1001
男人挣钱
true
但是其内存结构为栈空间中的m1和p2变量都指向同一个Man对象的址值值,但是由于m1声明为Man类型的,故m1可以调用堆空间子类的方法和属性。而p2声明为Person类,只能调用父类中的方法和属性。
与基本数据类型的强制类型转换和自动类型提升做一个对比
以下图直接采用尚硅谷的图
但是强制类型转换不能随便乱用,有时候编译器不报错,但运行起来会出现ClassCastException类型转换异常。
package com.atguigu.java4;
public class PersonTest {
public static void main(String[] args) {
Person p2 = new Man();
Man m1 = (Man)p2;
m1.isSmoking = true;
Woman w1 = (Woman)p2;
w1.goShopping();
}
}
运行结果为
Exception in thread “main” java.lang.ClassCastException: com.atguigu.java4.Man cannot be cast to com.atguigu.java4.Woman
at com.atguigu.java4.PersonTest.main(PersonTest.java:8)
这是因为p2本身所指向的堆空间本身就不具备goshopping这个方法
因此在进行强制类型转换的时候,为了确保转换的成功,引入了instanceof关键字。
instanceof关键字的用法
- 用法为 a instanceof A,判断a对象是否为A类的实例,是则返回true,不是则返回false
- 如果 a instanceof A 返回true,且B是A的父类,则a instanceof B也返回true。
代码如下
package com.atguigu.java4;
public class PersonTest {
public static void main(String[] args) {
Person p2 = new Man();
if(p2 instanceof Woman){
Woman w1 = (Woman)p2;
w1.goShopping();
System.out.println("***woman****");
}
if(p2 instanceof Man){
Man m1 = (Man)p2;
m1.earnMoney();
System.out.println("***man****");
}
}
}
运行结果为
男人挣钱
man*
特别强调 p2 instanceof Man,是看p2指向的堆空间对象是否为Man对象
因为
Person p2 = new Man();
在使用多态性的时候,已经声明了p2类指向堆空间的一个Man对象,故p2 instanceof Man的返回值为true。如此,就避免了在运用强制类型转换从父类的引用中调用子类方法和属性的时候,出现的ClassCastException类型转换异常。