多态
多态就是同一个方法可以根据发送对象的不同采取多种不同的行为方式。一个对象的实际类型是确定的,但是它能指向的引用类型有很多,它能够被它的父类(直接父类和间接父类)所接收。
多态存在的条件:
- 有继承关系。
- 子类重写父类方法。
- 父类引用指向子类对象。
父类Person
public class Person {
//父类打印方法
public void print() {
System.out.println("Person方法");
}
}
子类Student
public class Student extends Person {
@Override//表示该方法为重写方法
public void print() {
System.out.println("Student方法");
}
}
测试类Application
public class Application {
public static void main(String[] args) {
//创建学生对象 用父类引用接收
Person s1 = new Student();
//调用print方法
s1.print(); //Student方法
}
}
我们在测试类中可以看到,创建了一个学生对象,但是我们采用了其父类类型接收其引用,这就是子类对象指向父类引用。我们在子类中重写了父类的print方法,所以s1.print()执行的是子类的方法。如果父类中没有此方法,s1.print();
会报错,编译不通过。如果子类中没有重写该方法,运行时就会执行父类的方法,则不能体现出多态。
这里就能用“编译看左边,运行看右边”来解释:
- 编译看左边:
编译时,Java编译器会检查接收对象(左边的Person s1)是否有该方法(print()),如果没有,则编译不通过。 - 运行看右边:
运行时,JVM会运行实际创建对象(右边的new Student())的方法,如果子类无该方法,则调用父类的方法。
多态是方法的多态,属性没有多态。
instanceof
instanceof
:运算符;
instanceof
是Java保留的关键字。它的作用是检测它左边的对象是否是它右边的类的实例,如果是,则返回true,如果不是,则返回false。
Person的另一个Teacher子类:
public class Teacher extends Person {
@Override
public void print() {
System.out.println("Teacher的方法");
}
}
Student的一个MathStudent子类:
public class MathStudent extends Student {
@Override
public void print() {
System.out.println("MathStudent的方法");
}
}
测试代码:
//创建学生对象 用父类引用接收
Person s1 = new Student();
System.out.println(s1 instanceof Student);//true
System.out.println(s1 instanceof MathStudent);//false
System.out.println(s1 instanceof Teacher);//false
System.out.println(s1 instanceof Person);//true
System.out.println(s1 instanceof Object);//true
//System.out.println(s1 instanceof String);//编译报错
instanceof关键字,用于判断一个左边的实例对象是否是右边的类。
- 如果实例对象不能转化为右边的类对象,则编译不通过(两者无关)。
- 如果实例对象能够转化为右边的类对象,并且其真实对象(new时候的类型)不是右边的类或者子类,则返回false(非直系亲戚)。
- 如果实例对象能够转化为右边的类对象,并且其真实对象是右边的类或者是右边类的子类,则返回true(直系亲戚)。
引用类型转换
在Java中,我们也能对引用类型进行转换,当然这种转换是需要条件的,引用类型转换之间的类必须存在父子关系,才能编译通过。
引用类型和基本数据类型类似,高到低需要强制转换,低到高则能自动转换。这里的高类型就是“辈分”高的类型。
- 如果将一个类对象转换为其父类类型,则可以自动转换。
- 如果将一个类对象装换为其子类类型,运行时出现转化异常(java.lang.ClassCastException)。
- 如果一个类对象转换为与其不相关的类类型,编译不通过。
比如上图:
Student类对象能在它所属的那条直线上(Object<–Person<–Student<–MathStudent)随意转换,但是它转换为MathStudent时运行会出错。它就不能转换为与其不在同一条直线上的类型,比如它转换为Teacher类型时编译就会出错。