Java多态性
多态是指父类中定义的方法被子类继承之后,可以表现出不同的行为,这使得同一个方法在父类及其各个子类中具有不同的含义。
Java 实现多态有 3 个必要条件:继承、重写和向上转型。
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型(父类对象指向子类引用):在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。
多态中的成员的访问特点
多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的.
看下面的例子:
public class Animal {
public int age = 3;
public void eat(){
System.out.println("动物进食.....");
}
}
public class Cat extends Animal{
public int age = 2;
public int weight = 10;
@Override
public void eat(){
System.out.println("猫吃鱼...");
}
public void palyGame(){
System.out.println("猫抓老鼠玩....");
}
}
public class Dog extends Animal{
public int age = 4;
public String name = "旺财";
@Override
public void eat(){
System.out.println("狗吃骨头....");
}
public void work(){
System.out.println("狗看家....");
}
}
public class AnimalTest {
public static void main(String[] args) {
// 父类引用指向子类对象
Animal a1 = new Cat();
a1.eat();// 猫吃鱼
//a1.palyGame();//访问不到
System.out.println(a1.age);//3
Animal a2 = new Dog();
a2.eat();//狗吃骨头
System.out.println(a2.age);//3
}
}
成员方法:
看左边,看的是父类的引用(看父类中是否具有该成员方法)
看右边,看的是子类的对象(实际运行时的子类重写父类的方法)
成员变量:不具备多态性,只要看引用变量声明的类型即可。
成员方法:编译看左边 运行看右边
成员变量:编译看左边 运行看左边
使用多态的利弊
好处:提高了代码的扩展性。定义方法的时候,使用的是父类型作为参数,在使用是的时候,可以使用具体的子类作为真是的操作对象
弊端:不能访问子类特有的成员。
animal.str = ""; // 编译出错,提示Animal类中没有str属性
animal.eatMethod(); // 编译出错,提示Animal类中没有eatMethod()方法
若想要要调用子类的特有成员,就要使用到对象的转型
((Cat)animal).str = ""; // 编译成功
((Cat)animal).eatMethod(); // 编译成功
对象类型转换:向上转型和向下转型
将一个类型强制转换成另一个类型的过程被称为类型转换。
对象类型转换,是指存在继承关系的对象,不是任意类型的对象。当对不存在继承关系的对象进行强制类型转换时,会抛出 Java 强制类型转换(java.lang.ClassCastException)异常。
Dog dog = new Dog();
Cat cat = (Cat)dog; // 编译出错,不允许把Dog对象类型转换为Cat对象类型
1)向上转型
父类引用指向子类对象为向上转型,语法格式如下:
fatherClass obj = new sonClass();
其中,fatherClass 是父类名称或接口名称,obj 是创建的对象,sonClass 是子类名称。
向上转型就是把子类对象直接赋给父类引用,不用强制转换。使用向上转型可以调用父类类型中的所有成员,不能调用子类类型中特有成员,最终运行效果看子类的具体实现。
2)向下转型
与向上转型相反,子类对象指向父类引用为向下转型,语法格式如下:
sonClass obj = (sonClass) fatherClass;
其中,fatherClass 是父类名称,obj 是创建的对象,sonClass 是子类名称。
向下转型可以调用子类类型中所有的成员,不过需要注意的是如果父类引用对象指向的是子类对象,那么在向下转型的过程中是安全的,也就是编译是不会出错误。但是如果父类引用对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现我们开始提到的 Java 强制类型转换异常,一般使用 instanceof 运算符来避免出此类错误。
Animal animal = new Dog(); // 向上转型,把Dog类型转换为Animal类型
Dog dog = (Dog) animal; // 向下转型,把Animal类型转换为Dog类型
Animal animal = new Cat();
if (animal instanceof Cat) {
Cat cat = (Cat) animal; // 向下转型
...
}
instanceof关键字
Java 中可以使用 instanceof 关键字判断一个引用是否为一个类(或接口、抽象类、父类)的实例,返回值为boolean类型,语法格式如下所示。
boolean result = obj instanceof Class