秦疆的JavaSE课程笔记:72 面向对象 instanceof和类型转换
instanceof
关键字,用于判断左边的对象是否属于右边的类。- 先创建4个类,父类
Person
,其子类Student
和Teacher
,测试类Application
。在Application
中测试instanceof
语句:
//父类
public class Person {}
//子类
public class Teacher extends Person {}
//子类
public class Student extends Person {}
//测试类
import OOP.demo.Person;
import OOP.demo.Teacher;
import OOP.demo.Student;
public class Application {
public static void main(String[] args) {
Object a = new Student();
System.out.println(a instanceof Student);
System.out.println(a instanceof Person);
System.out.println(a instanceof Object);
System.out.println(a instanceof Teacher);
System.out.println(a instanceof String);
}
}
====运行结果====
true
true
true
false
false
-
上述代码存在三条继承关系:
- Object>Person>Teacher
- Object>Person>Student
- Object>String
-
首先,
a
本身属于Object
引用类型,调用的是Student
类的构造器,也就是Student
类的实例对象,按照instanceof
“判断左边的对象是否属于右边的类”的功能,所以判断的是Student
对象(而非Object
类)是否属于列举的类,当然,属于父类Person
和Object
,但不属于Teacher
和String
。 -
其次,
a
作为一个Object
类,是可以强制转换为其他子类,所以编译不会报错。 -
将
Object a = new Student();
改为Person b = new Student();
,a
替换为b
,其余不变。
import OOP.demo.Person;
import OOP.demo.Teacher;
import OOP.demo.Student;
public class Application {
public static void main(String[] args) {
Person b = new Student();
System.out.println(b instanceof Student);
System.out.println(b instanceof Person);
System.out.println(b instanceof Object);
System.out.println(b instanceof Teacher);
//System.out.println(b instanceof String); 报错:不可转换的类型
}
}
====运行结果====
true
true
true
false
-
不可转换的原因是,
b
属于Person
引用类型,和String
虽然同属Object
的子类,但是相互之间没有继承关系,无法转换,故而报错 -
再将
Person b = new Student();
改为Student c = new Student();
,b
替换为c
,其余不变。
import OOP.demo.Person;
import OOP.demo.Teacher;
import OOP.demo.Student;
public class Application {
public static void main(String[] args) {
Student c = new Student();
System.out.println(c instanceof Student);
System.out.println(c instanceof Person);
System.out.println(c instanceof Object);
//System.out.println(c instanceof Teacher); 报错:不可转换的类型
//System.out.println(c instanceof String); 报错:不可转换的类型
}
}
====运行结果====
true
true
true
-
报错的原因同上。
-
我自己的小结:
X a = new Y();
语句,决定了a
的引用类型X
,和调用的构造器Y()
,也就是说,a
是Y
类的实例对象。前提是类型X
是类型Y
的父类或者本身。a instanceof Z
语句,是看对象a
是否从属于右边的类Z
,看的是a
调用的构造器Y()
所属的类型Y
和Z
类型的继承关系。有关则为true,无关则为false。- 而报错与否看的是
a
引用类型X
和Z
类型的继承关系,没有继承关系则无法相互转换,故而报错。(这应该涉及到instanceof关键词的底层原理)
-
类型转换
//父类
public class Person {
public void run() {
System.out.println("run");
}
}
//子类
public class Student extends Person {
public void go() {
System.out.println("go");
}
}
//测试类
import OOP.demo.Person;
import OOP.demo.Student;
public class Application {
public static void main(String[] args) {
Person a = new Student();
//a.go(); 报错,父类无法调用子类的方法
//通过强制转换,将父类转换为子类
Student b = (Student) a;
b.go();
}
}
-
高转低(父转子),要通过强制转换。
-
当然,也可以使用
((Student) a).go
将上述两句合成一句,没有必要再创建一个变量。 -
沿用上面的代码,在测试类中试验子类转父类。
import OOP.demo.Person;
import OOP.demo.Student;
public class Application {
public static void main(String[] args) {
Student a = new Student();
a.go(); //子类调用自己的方法,没有问题
Person b = a; //子类转父类自动转换,不需要强制转换
//b.go(); 报错,转换为父类后无法调用子类的方法。
}
}
-
子类转换为父类,可能会丢失子类的方法。
-
总结:
- 父类引用指向子类的对象
- 子类转换为父类(向上转型),不用强制转换
- 父类转换为子类(向下转型),需要强制转换
- 方便方法的调用,减少重复的代码