- 什么是多态
在介绍多态之前,首先我们要明白多态是基于java中继承的延申,所以我们先创建一个子类与父类
public class Mammal{
public void move() {
System.out.println("移动");
}//创建父类,添加方法move
}
public class Whale extends Mammal{
}
//创建子类,继承父类
我们知道,在java中有着数据类型的自动转换,比如 double price = 9,在这里,9其实是一个int类型,但可以通过这段代码使其转化为double类型,而其实java中的对象也有着相似的操作
public class Mammal{
public void move() {
System.out.println("移动");
}
}
public class Whale extends Mammal{
public void move() {
System.out.println("用鳍摆动移动");//重写move方法
}
public static void main(String[] args) {
Mammal mammal = new Whale();//自动类型转换:父类类型的变量指向其子类创建的对象 对象上转型 new Whale()上转型对象
mammal.move();//调用父类move方法
}
}
正常情况下,我们创建子类对象应该用 Whale whale = new Whale();语句,但是在最后这段代码中,我们创建的子类对象是由父类类型的变量所指向的,这就叫做对象上转型。虽然我们重写了父类的方法,但最后我们调用的仍然是父类方法,那么最终输出什么呢?
我们看到,明明调用的是父类的方法,但由于该对象实质上仍然是子类所创建的,只是被父类变量所指向,执行时由于mammal存的是子类创建的对象,所以执行时执行的是子类中的方法。我们把这种现象称之为多态。
- 注意事项
同时需要注意的是,我们把Mammal mammal = new Whale()等号的左边叫做编译体,右边叫做执行体,所以代码的编译在父类中进行,而执行在子类中进行,这也就导致了一件事情:父类中没有而子类中新增的方法和属性,不能被上转型对象调用
public class Mammal{
public void move() {
System.out.println("移动");
}
}
public class Whale extends Mammal{
public void move() {
System.out.println("用鳍摆动移动");//重写move方法
}
public void eat(){
System.out.println("吃东西");//新增eat方法
}
public static void main(String[] args) {
Mammal mammal = new Whale();//创建上转型对象
mammal.move();
mammal.eat();//调用eat方法
}
}
在这段代码中我们在子类里新增了父类所没有的eat方法,程序报错,这其实是因为父类中没有该方法,于是在编译的时候就出现了问题,因此我们会发现mammal根本无法调用eat方法(新增属性也是如此,不再另外举例)
那么如果我们想要让子类中新增的方法和属性被上转型对象调用,该怎么做呢?
答案:将上转型对象进行下转型
public class Mammal{
public void move() {
System.out.println("移动");
}
}
public class Whale extends Mammal{
public void move() {
System.out.println("用鳍摆动移动");//重写move方法
}
public void eat(){
System.out.println("吃东西");//新增eat方法
}
public static void main(String[] args) {
Mammal mammal = new Whale();//创建上转型对象
mammal.move();
Whale whale = (Whale)mammal;//进行下转型
whale.eat();//调用eat方法
}
}
我们使用的下转型语句Whale whale = (Whale)mammal 将子类对象重新转型为本类变量所指向的对象,因此就可以调用本类的新增对象和属性了
另外,需要记住,在进行下转型之前必须先有上转型对象,否则就是简单的本类对象了,没有对象转型一说。
- 多态的拓展
由于子类重写了方法,且进行了对象上转型操作后,执行的是子类的重写方法,父类的被重写方法其实没有意义,因此我们可以说多态的前提下,父类中被子类重写的方法没有必要有方法体
public class Mammal{
public void move() {
}//没有方法体的父类方法
}
public class Whale extends Mammal{
public void move() {
System.out.println("用鳍摆动移动");
}
public static void main(String[] args) {
Mammal mammal = new Whale();
mammal.move();//重写move方法后将子类对象上转型然后调用move方法
}
}
像这样,程序一样可以正常运行,而这种情况下,我们可以在父类没有方法体的方法的访问控制符与修饰符之间加上abstract关键词使其变为抽象方法,而如果一个类中含有了抽象方法,那么就必须用abstract修饰,成为抽象方法
public abstract class Mammal{//因为含有抽象方法,该类必须加上abstract关键字成为抽象类
public abstract void move() {
}//没有方法体的父类方法加上abstract关键字成为抽象方法
}
public class Whale extends Mammal{
public void move() {
System.out.println("用鳍摆动移动");
}
public static void main(String[] args) {
Mammal mammal = new Whale();
mammal.move();//
}
}
并且,如果一个抽象类下全都是抽象方法,我们就可以把它称为接口。