instanceof可以用来判断一个对象是什么类型。
包含四个类的代码作为父类的Person以及作为其子类的两个类分别为Student类以及Teacher类还有运行的主类。主类包含两次运行,此次以Application1以及Application2来进行区分。
package com.oop.demo06; public class Student extends Person{ public void go(){ System.out.println("go"); } } / package com.oop.demo06; public class Person { public void run(){ System.out.println("run"); } } / package com.oop.demo06; public class Teacher extends Person{ }
上方依次为Student,Person,Teacher类的相关代码。对于有关instanceof函数的首个Application1的相关代码如下。
//Object>String //Object>Person>Teacher //Object>Person>Student //System.out.println(X instanceof Y);能不能编译通过看X定义义语句左边类(引用类型)与Y是否存在父子关系,而结果是true还是false取决于对象X定义语句右边类(实际类型)是否与Y类存在父子关系 Object object = new Student(); Object s = new Person(); //实际类型为=右边的类型判断是否编译报错要看=左边的类型是否与要判断的类相关 //因为为new Student()所以object实际上为Student类的实例 //因为object为Student故而也一定是Person类从而也一定是Object类但是必须明白实际上首先为Student类 System.out.println(s instanceof Student);//false System.out.println(object instanceof Student);//True System.out.println(object instanceof Person);//True System.out.println(object instanceof Object);//True System.out.println(object instanceof Teacher);//False System.out.println(object instanceof String);//False System.out.println("======================"); Person person = new Student(); System.out.println(person instanceof Student);//True System.out.println(person instanceof Person);//True System.out.println(person instanceof Object);//True System.out.println(person instanceof Teacher);//False //System.out.println(person instanceof String);//编译报错因为instanceof要求对应的两个类要有包含关系此时的对象类型指的是左边的实际类型 System.out.println("======================"); Student student = new Student(); System.out.println(student instanceof Student);//True System.out.println(student instanceof Person);//True System.out.println(student instanceof Object);//True //System.out.println(student instanceof Teacher);//编译报错 //System.out.println(student instanceof String);//编译报错
首先对于instanceof的用法如下:X instanceof Y ,其中X为对象名字,Y为要进行判断的类的名字,如果X与Y为同一类型或者X所在类为Y的子类则返回true,否则返回false,但是要注意X与Y必须有包含关系才会返回true或者false否则会显示编译报错。故而要先判断是否为编译错误,再判断返回值是true还是false.对于编译错误以及返回值的判断规则为(针对定义语句而言):编译看左,运行看右。对于定义语句例子:Object s = new Person();其中s即为X编译看定义语句左边也就是说为引用类型的具体情况,此时左边为Object类,此时一定不会报错,因为Object类为所有类的父类一定满足编译要求。再比如Person person = new Student();编译看左此时引用类型为Person类,若为person(X) instance String则为编译错误,因为Person类与String类绝对不在同一个类树下,也就是说二者不存在包含关系,故而报错。
再者对于运行看右:例如Person person = new Student();此时看右边表示实际类型为Student类,而其实要判断的就是对象X是否为Y类(或者X是否为Y的子类,祖宗类。实际为看Y是否包含X),若是则返回true否则返回false.例如student instanceof Student此时对象student实际类型就是Student类故而返回true,而对于student instanceof Person对象student实际类型Student为Person的子类故而返回true同理student instanceof Object也返回true.再比如Object s = new Person();对象s的实际类型为Person类故而s instanceof Student的返回类型为false因为Y是X的子类故而Y不包含X返回false.
其次对于类型转换的Application2类的代码如下:
package com.oop; import com.oop.demo06.Person; import com.oop.demo06.Student; public class Application1 { public static void main(String[] args) { //类型之间的转换:父类(高) 子类(低) //高 低 //子类型转换为父类型可能(因为多态和重写的存在)将丢失自己本来的一些方法 Person obj = new Student(); //obj将这个对象转换为Student类型就可以使用Student类型的方法run()了! //把Person类(高)转换为Student类(低)要进行强制转换 //Student student=(Student)obj;//将强制转换为Student类型的obj对象赋值给Student类型的student对象无报错故转换正常且可以用student对象调用go()方法 ((Student)obj).go();//注意外层括号必须加上否则还是认为是未转换的obj对象在调用go()方法 Student student = new Student(); student.go(); Person person = student;//为低转高类型可以直接转换但是转换之后就只能按高类型处理 //此处为将低类型Student对象student转换为高类型Person的person对象且此时person.go()将报错 } }
对于定义语句Person obj = new Student();可视为对于主类Person对象obj的扩充,除了能调用obj的属性或者方法,还能调用其子类Student的重写方法。但是要想调用Student的其它属性或者方法,必须将obj转换为Student类才行,此时obj为父类型为(高等级)而Student为子类型(低等级)故而由高转低必须进行强制类型转换,具体类似于基本类型转换。例如:/Student student=(Student)obj;此时理解为:将强制转换为Student类型的obj对象赋值给Student类型的student对象无报错故转换正常且可以用student对象调用go()方法,即为student.run();但是也可以不用赋值直接转换后调用,即为((Student)obj).go();注意外层括号必须加上,否则还是认为是未转换的obj对象在调用go()方法。将会报错。
对于有低等级(子类型)转换为高等级(父类型)则不需要强制转换直接进行赋值处理即可例如:Person person = student;将子类型对象student直接赋值给其父类型Person对象person,但是实际上一般不需要进行这样的转换,因为子类型一般都可以对父类型的方法以及属性进行调用,除非被private等修饰词修饰时可能需要转换,否则一般不要使用,因为将会丢失调用子类型的方法的后果。
多态的再次总结:
1.前提:父类引用指向子类的对象,此时(类型转换)也一样:Person person = student; 2.把子类转化为父类,向上转型:不用强制转换为直接转换即可,可能丢失方法 3.把父类转化为子类,向下转型:需要强制转换,(父类转换为子类会令父类被重写的方法无法执行调用重写方法名时,只会执行子类的重写方法。) 4.方便方法的调用,减少重复的代码,更为简洁
此时抽象三大特性:封装,继承,多态已经讲完,还有更为抽象的抽象类以及更为抽象的接口下两节再分别讲解。