多态
多态是Java的三大特性之一(封装、继承、多态)。
多态:就是多种形态。多态是建立在封装和继承的基础之上的
。
多态可以分为:方法的多态【非重点】和对象的多态【重点】。
方法的多态【非重点】
方法的重写和重载都是方法多态的表现
package com.lyc.lesson;
class Person {
public void eat () {
System.out.println("吃饭");
}
public void eat (String food) {
System.out.println("吃" + food);
}
}
//继承
class Man extends Person {
//重写
@Override
public void eat() {
System.out.println("吃枸杞");
}
@Override
public void eat(String food) {
System.out.println("吃"+ food);
}
}
public class Demo1 {
public static void main(String[] args) {
}
}
对象的多态【重点】
在讲对象的多态之前我们要先了解到,一个对象的编译类型和运行类型是不一样的。
编译类型是在定义对象的时候就已经确定好的,不可改变。
运行类型是可以改变的。
如何区分什么是编译类型,什么是运行类型?如下图
多态:指父类的引用指向子类对象。
package com.lyc.lesson;
class Animal{
}
class Dog extends Animal{
}
public class Lesson01 {
public static void main(String[] args) {
/**
* 多态:父类的引用指向子类的对象
* 父类的引用 = 子类的对象
* Animal animal = new Dog();
*/
Animal animal = new Dog();
}
}
我们知道,多态是在继承的基础之上来实现的。如上述案例,父类Animal,子类Dog。根据多态的定义,我们可以初步写出多态的基本形式。
多态的注意事项:
1、必须有继承
2、必须有方法的重写。
3、父类的引用是无法指向子类独有的方法,这就意味着,父类的引用不能调用子类独有的方法。
即,多态能调用父类中已经重写的方法,子类独有的方法的方法无法调用。
4、Person person = new Student(); 等号左边是父类引用,等号右边是子类对象。
package com.lyc.lesson;
class Manager{
public void excute(Person person) {
person.excute();
}
}
class Person{
public void excute() {
System.out.println("执行");
}
}
class Student extends Person{
@Override
public void excute() {
System.out.println("执行学员手册");
}
public void study() {
System.out.println("学生努力学习");
}
}
public class Lesson02 {
public static void main(String[] args) {
Person person = new Student();
Manager manager = new Manager();
manager.excute(person);
/**
* 父类的引用是无法指向子类独有的方法,这就意味着,父类的引用不能调用子类独有的方法
* 即,多态能调用子类中已经重写的方法,子类独有的方法的方法无法调用
*/
manager.study(); //报错
}
}
多态的转型【重点】
多态的转型分为了:向上转型和向下转型。
向上转型
向上转型的本质:父类的引用指向子类对象。
语法格式
父类 父类引用 = new 子类对象。 Person person = new Student();
解析:
将子类的对象赋值给了父类的引用。小范围(子类) 转向 大范围(父类),因此是自动转型。
同时,父类引用可以调用父类中的所有方法和子类中重写的方法,凡是不能调用子类中独有的方法。前面已举过例子,这里就不在举例。
向下转型
向下转型的本质:就是把父类对象转为子类对象。
但是要注意,这里的转型不能使用一般的强制类型转换,
如:Cat cat = (Cat) new Animal(); 这样虽然编译会通过,但是运行时,就会报错。如图:
package com.lyc.lesson;
class Animal2{
public void eat() {
System.out.println("吃饭");
}
}
class Cat extends Animal2{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Lesson04 {
public static void main(String[] args) {
/**
* 报错,类型转换错误
* Exception in thread "main" java.lang.ClassCastException: class com.lyc.lesson.Animal2 cannot be cast to class com.lyc.lesson.Cat (com.lyc.lesson.Animal2 and com.lyc.lesson.Cat are in unnamed module of loader 'app')
at com.lyc.lesson.Lesson04.main(Lesson04.java:23)
*/
// 错误的向下转型
// Animal2 animal2 = new Animal2();
// Cat cat = (Cat) animal2;
// cat.eat();
//安全的向下转型:先向上转,再向下转
Animal2 animal2 = new Cat();
Cat cat = (Cat) animal2;
cat.eat();
}
}
为了解决这样的问题,我们对于
多态的向下转型
一般采用的方式为:先向上转型,再向下转型
。如以上的案例。这样的向下转型方式,才是正确的向下转型。
at.eat();
//安全的向下转型:先向上转,再向下转
Animal2 animal2 = new Cat();
Cat cat = (Cat) animal2;
cat.eat();
}
}
> 为了解决这样的问题,我们对于`多态的向下转型`一般采用的方式为:`先向上转型,再向下转型`。如以上的案例。这样的向下转型方式,才是正确的向下转型。
>
> 而多态的向下转型就可以解决多态的弊端,即解决了多态无法调用子类特有的方法的弊端。