多态
面向对象:封装,继承,多态
extends继承或者implements实现,是多态性的前提
小明是一个学生,也是一个人。一个对象拥有多种形态,这就是对象的多态性
多态的格式和使用
代码当中体现多态性,其实就是一句话,父类引用指向子类对象
【格式:】
父类名称 对象名 = new 子类名称();
或者
接口名称 对象名 = new 实现类名称();
package Demo13;
public class Fu {
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有");
}
}
package Demo13;
public class Zi extends Fu {
@Override
public void method(){
System.out.println("子类方法");
}
}
package Demo13;
public class Multi {
public static void main(String[] args) {
//使用多态的写法
//左侧父类的引用,指向了右侧子类的对象
Fu obj = new Zi();
obj.method();
obj.methodFu();
}
}
访问成员变量的两种方式
- 直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有 向上找
- 间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有 向上找
package Demo14;
public class Fu {
int num = 10;
public void showNum(){
System.out.println(num);
}
}
package Demo14;
public class Zi extends Fu{
int num = 20;
int age = 20;
@Override
public void showNum(){
System.out.println(num);
}
}
package Demo14;
public class Muntifield {
public static void main(String[] args) {
//使用多态的方法,父类引用指向子类对象
Fu obj = new Zi();
System.out.println(obj.num);
//错误写法,父类里没有age
// System.out.println(obj.age);
//子类没有覆盖重写,就是父 10
//子类如果覆盖重写,就是子20
obj.showNum();
}
}
多态中成员方法的使用特点
-
在多态代码中,,成员方法的访问规则是:
- 看new的是谁,就优先用谁,没有则向上找
-
口诀:
- 编译看左边,运行看右边4
-
对比:
- 成员变量:编译看左边,运行还看左边
- 成员方法:编译看左边,运行看右边
package Demo14;
public class MultMethod {
public static void main(String[] args) {
Fu obj = new Zi(); //多态
obj.method(); //父子都有,优先用子
obj.methodFu(); //子类没有,父类有,向上找到父类使用
//编译看左边,左边是是Fu,Fu当中没有methodZi方法,所以报错
// obj.methodZi(); //错误写法!
}
}
使用多态的好处
对象的向上转型
-
对象的向上转型,其实就是多态写法:
- 格式:父类名称 对象名 = new 子类名称();
- 含义:右侧创建一个子类对象,把他当作父类来看待使用
- 注意事项:向上转型一定是安全的,因为是从小范围转向了大范围。
- 弊端:一旦向上转型为父类,那么就无法调用子类原本特有的方法
Animal animal = new Cat(); 从小范围的猫,向上转换成为更大的动物
package Demo14;
public abstract class Animal {
public abstract void eat();
}
package Demo14;
public class Cat extends Animal {
@Override
public void eat(){
System.out.println("猫吃鱼");
}
}
package Demo14;
public class Main {
public static void main(String[] args) {
//对象的向上转型,就是,父类引用指向子类对象
Animal animal = new Cat();
animal.eat();
}
}
对象的向下转型
向上转型一定是安全的,因为是从小范围转向了大范围。弊端:一旦向上转型为父类,那么就无法调用子类原本特有的方法
解决方案:用对象的向下转型【还原】
-
对象的向下转型,其实是一个【还原】的动作
-
格式
- 子类名称 对象名 = (子类名称)父类对象;
-
含义
-
将父类对象,【还原】成为本来的子类对象
-
Animal animal = new Cat(); //本来是猫,向上转型成为动物
Cat cat = (Cat) animal; //本来是猫,已经被当作动物了,还原回来成为原来的猫
-
-
注意事项
- 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫
- 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错java.lang.ClassCastException
package Demo14;
public class Cat extends Animal {
@Override
public void eat(){
System.out.println("猫吃鱼");
}
public void catMouse(){
System.out.println("猫抓老鼠");
}
}
package Demo14;
public class Dog extends Animal {
@Override
public void eat(){
System.out.println("狗吃骨头");
}
public void watchHoyse(){
System.out.println("狗看家");
}
}
package Demo14;
public abstract class Animal {
public abstract void eat();
}
package Demo14;
public class Main {
public static void main(String[] args) {
//对象的向上转型,就是,父类引用指向子类对象
Animal animal = new Cat(); //本来创建的时候就是猫
animal.eat(); //猫吃鱼
//向下转型
Cat cat = (Cat) animal;
cat.catMouse();
//下面是错误的向下转型
//本来new的时候是一只猫,现在非要当成狗
//错误写法!编译不会报错,但是运行会出现异常
//java.lang.ClassCastException
Dog dog = (Dog) animal;
}
}
instanceof关键字
如何才能知道一个父类引用的对象,本来是什么类?
-
格式:
对象 instanceof类型
这将会得到一个boolean值结果,也就是判断前面的对象能不能当最后面类型的实例
package Demo14;
public class Demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Cat(); //本来是一只猫
animal.eat(); //猫吃鱼
//如果希望调用子类特有的方法,需要向下转型
//判断一下父类animal本来是不是Dog
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHoyse();
}
//判断一下animal本来是不是Cat
if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catMouse();
}
}
}