概念:同一个类实例的相同方法在不同情形下有不同的表现形式
在Java中,对于多态的核心表现主要有以下两点:
1. 方法多态:
① 方法重载:同一个方法名称可以根据参数的类型或个数不同调用不同的方法体
② 方法覆写:同一个父类的方法可以根据实例化子类的不同也有不同的实现
方法多态之前的文章里面详细阐述过,在此不再赘述。
2. 对象多态:
① 向上转型(90%):
天然发生,认爹过程,指的是将子类对象变成父类对象
语法:父类 父类引用 = 子类实例;
,例如Person per = new Student();
class Person {
public void print() {
System.out.println("父类");
}
}
class Student extends Person {
public void print() {
System.out.println("子类");
}
}
public class XiangShangZhuanXing {
public static void main(String[] args) {
Person per = new Student();
per.print();
}
}
- 结论:不管是否发生了向上转型,核心本质还是在于:你使用的是哪一个子类(new在哪里),而且调用的方法是否被子类所覆写了。
应用场景:参数统一化
例如:要求定义一个方法,这个方法可以接收Person类的所有子类实例,并调用Person类的方法。
class Person {
public void print() {
System.out.println("1.我是人类!");
}
}
class Student extends Person {
public void print() {
System.out.println("2.我是学生!");
}
}
class Worker extends Person {
public void print() {
System.out.println("3.我是工人!");
}
}
public class CanShuTongYiHua {
public static void main(String[] args) {
//Person per = new Student();
WhoYouAre(new Student());
//Person per = new Worker();
WhoYouAre(new Worker());
}
public static void WhoYouAre(Person per) {
per.print();
}
}
② 向下转型(1%):
需要强转,指的是将父类对象变成子类对象
语法:子类 子类实例 = (子类)父类实例;
,例如Student stu = (Student) per;
class Person {
public void print() {
System.out.println("父类");
}
}
class Student extends Person {
public void print() {
System.out.println("子类");
}
public void fun() {
System.out.println("只有子类有");
}
}
public class XiangXiaZhuanXing {
public static void main(String[] args) {
Person per = new Student();
per.print();
System.out.println("==========");
Student stu = (Student) per;
stu.fun();
}
}
- 结论:在上述代码中父类能调用的就只有本类定义好的方法,并没有Student类中的
fun()
方法,如果父类要想调用fun()
方法就只能进行向下转型处理,总的来说就是当需要子类扩充操作的时候就要采用向下转型。
应用场景:发生在父类引用需要调用子类扩充方法时,才发生向下转型变为子类引用调用其扩充方法
注意:并不是所有的父类对象都可以向下转型 ,如果要想进行向下操作之前,前提是一定要首先发生向上转型,否则在转型时会出现ClassCastException(运行时异常,类型转换异常,发生在两个毫无关系的两个类之间的强转时)
观察错误转型:
class Person {
public void print() {
System.out.println("父类");
}
}
class Student extends Person {
public void print() {
System.out.println("子类");
}
public void fun() {
System.out.println("只有子类有");
}
}
public class XiangXiaZhuanXing {
public static void main(String[] args) {
Person per = new Person();
per.print();
System.out.println("==========");
Student stu = (Student) per;
stu.fun();
}
}
最好的做法就是先进行判断,而后再进行转型,那么就可以依靠关键字instanceof实现。
引用对象 instanceof 类:表示该引用能指向该类,返回true表示可以指向,返回flase表示不能指向。
因此,向下转型的标准格式为:
if(!(per instanceof Student)) {
per = new Student(); // 先建立起联系
}
Student stu = (Student) per;
观察instanceof操作:
class Person {
public void print() {
System.out.println("父类");
}
}
class Student extends Person {
public void print() {
System.out.println("子类");
}
public void fun() {
System.out.println("只有子类有");
}
}
public class XiangXiaZhuanXing {
public static void main(String[] args) {
Person per = new Person();
//避免ClassCastException
if(!(per instanceof Student)) {
per = new Student();
}
Student stu = (Student) per;
stu.fun();
}
}
- 结论:我们可以看到加上instanceof之后就算没有先向上转型,向下转型依然是可以进行的。
总结:
- 对象的多态性(向上转型或向下转型)本质在于方法的覆写。
- 通过对象的向上转型可以实现接收参数的统一,向下转型可以实现子类扩充方法的调用(一般不操作向下转型,有安全隐患)。
- 两个没有关系的类对象是不能够进行转型的,一定会出现ClassCastException。