多态
同种类型的对象,表现出的不同形态
形式
多态是出现在继承或者实现关系中的。
体现格式:
父类类型 变量名 = new 子类/实现类构造器;
变量名.方法名();
前提:继承/实现关系
有父类引用指向子类对象
有方法重写
使用场景
没有多态,在下图中register方法只能传递学生对象,其他的Teacher和administrator对象是无法传递给register方法方法的,在这种情况下,只能定义三个不同的register方法分别接收学生,老师和管理员。
有了多态之后,方法的形参就可以定义为共同的父类Person。
好处:使用父类类型作为参数,可以接收所有子类对象
体现多态的扩展与便利
注意:
调用成员的特点
- 变量调用:编译看左边,运行也看左边
- 方法调用:编译看左边,运行看右边
Fu f = new Zi();
//编译看左边的父类中有没有name这个属性,没有就报错
//在实际运行的时候,把父类name属性的值打印出来
System.out.println(f.name);
//编译看左边的父类中有没有show这个方法,没有就报错
//在实际运行的时候,运行的是子类中的show方法
f.show();
package day14.demo2;
public class demo2 {
public static void main(String[] args) {
animal a = new dog();
a.show();//dog
System.out.println(a.name);//animal
}
}
class animal{
String name = "animal";
public void show(){
System.out.println("animal");
}
}
class dog extends animal{
String name = "dog";
@Override
public void show() {
System.out.println("dog");
}
}
class cat extends animal{
String name = "cat";
@Override
public void show() {
System.out.println("cat");
}
}
多态的利弊
利:
多态形式下,右边对象可以实现解耦合,便于扩展和维护
定义方法的时候,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利
弊:
不能调用子类特有的功能(解决: 变回子类类型就可以了,类型转换)
类型转换:
向上转型(自动转换):
-
向上转型:多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。 当父类引用指向一个子类对象时,便是向上转型。 使用格式:
父类类型 变量名 = new 子类类型(); 如:Animal a = new Cat();
原因是:父类类型相对与子类来说是大范围的类型,Animal是动物类,是父类类型。Cat是猫类,是子类类型。Animal类型的范围当然很大,包含一切动物。所以子类范围小可以直接自动转型给父类类型的变量。
向下转型(强制转换):
-
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:
子类类型 变量名 = (子类类型) 父类变量名; 如:Aniaml a = new Cat(); Cat c =(Cat) a;
instanceof关键字:
当类型转换过程中,转换成其他类型就会报错(ClassCastException
,类型转换异常! )
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
}
}
因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。
为了避免ClassCastException的发生,Java提供了 instanceof
关键字,给引用变量做类型的校验,格式如下:
变量名 instanceof 数据类型
如果变量属于该数据类型或者其子类类型,返回true。
如果变量不属于该数据类型或者其子类类型,返回false。
转换前,我们最好先做一个判断
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat(); // 调用的是 Cat 的 eat
// 向下转型
if (a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
} else if (a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
instanceof新特性:
JDK14的时候提出了新特性,把判断和强转合并成了一行
//新特性
//先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d
//如果不是,则不强转,结果直接是false
if(a instanceof Dog d){
d.lookHome();
}else if(a instanceof Cat c){
c.catchMouse();
}else{
System.out.println("没有这个类型,无法转换");
}
exp(多态案例):
package day14.demo3;
public class Animal {
private String color;
private int age;
public Animal() {
}
public Animal(String color, int age) {
this.color = color;
this.age = age;
}
/**
* 获取
* @return color
*/
public String getColor() {
return color;
}
/**
* 设置
* @param color
*/
public void setColor(String color) {
this.color = color;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Animal{color = " + color + ", age = " + age + "}";
}
public String eat(String somthing){
return "吃"+somthing;
}
}
============
package day14.demo3;
public class Cat extends Animal{
public Cat() {
}
public Cat(String color, int age) {
super(color, age);
}
public void catchMouse(){
System.out.println("抓老鼠");
}
@Override
public String eat(String somthing) {
return getAge() + "岁" + getColor() + "色的猫狂吃" + somthing;
}
}
=============
package day14.demo3;
public class Dog extends Animal{
public Dog() {
}
public Dog(String color, int age) {
super(color, age);
}
@Override
public String eat(String somthing) {
return getAge() + "岁" + getColor() + "色的狗狂吃" + somthing;
}
public void lookHome(){
System.out.println("看家");
}
}
==============
package day14.demo3;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Person{name = " + name + ", age = " + age + "}";
}
public void keepPet(Animal animal,String something){
if (animal instanceof Dog dog) {//判断是否为dog 如果不是强转为Dog
System.out.println(this.age+"岁的"+this.name+"养了"+animal.getAge()+"岁的"+animal.getColor()+ dog.eat(something));
}else if (animal instanceof Cat cat){
System.out.println(this.age+"岁的"+this.name+"养了"+animal.getAge()+"岁的"+animal.getColor()+ cat.eat(something));
}
}
}
==============
package day14.demo3;
public class Main {
public static void main(String[] args) {
Person person = new Person("老王",30);
Cat cat = new Cat();
cat.setAge(2);
cat.setColor("red");
person.keepPet(cat,"猫粮");
Dog dog = new Dog();
dog.setAge(200);
dog.setColor("yellow");
person.keepPet(dog,"狗粮");
}
}