多态 instanceof关键字 final关键字 向下转型

文章目录

什么是多态?

定义: 是指同一行为,具有多个不同表现形式。

多态的体现

父类名称 变量名 = new 子类名称
变量名、。方法名

多态的实现方式有:
1、子承父类
2、接口实现
3、抽象类和抽象方法

使用多态的好处

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展性与便利。

多态中成员变量和成员方法的使用特点

口诀:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。
成员方法口诀含义:

public class Demo02MultiMethod {

    public static void main(String[] args) {
        Fu obj = new Zi(); // 多态

        obj.method(); // 父子都有,优先用子
        obj.methodFu(); // 子类没有,父类有,向上找到父类
        
//       obj.methodZi(); // 错误写法! 编译看左边,左边是Fu,Fu当中没有methodZi方法,所以编译报错。
    }
    

}

向上转型

对象的向上转型,其实就是:父类引用指向子类对象。
(比方说:创建了一只猫,把它当做动物看待。是小范围->大范围)
格式:父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();

public abstract class Animal {
    public abstract void eat();

}


public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 子类特有方法
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

public class Demo01Main {

    public static void main(String[] args) {
        // 对象的向上转型,就是:父类引用指向子类对象。
        Animal animal = new Cat(); 
        animal.eat(); // 猫吃鱼
}
}

向下转型

向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
对象一旦向上转型为父类,那么就无法调用子类特有的方法。

解决方案:用对象的向下转型【还原】。将父类对象,“还原”成本来的子类对象。
格式:子类名称 对象名 =(子类名称) 父类对象
Cat cat = (Cat)Animal;
Cat cat = Animal;

public abstract class Animal {
    public abstract void eat();

}


public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    // 子类特有方法
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}
public class Demo01Main {

    public static void main(String[] args) {
        // 对象的向上转型,就是:父类引用指向子类对象。
        Animal animal = new Cat(); // 本来创建的时候是一只猫
        animal.eat(); // 猫吃鱼
        // 向下转型,进行“还原”动作
        Cat cat = (Cat) animal;
        cat.catchMouse(); // 猫抓老鼠
    }

}

instanceof关键字

使用instanceof关键字将会得到一个boolean值结果,也就是判断前面的创建对象。
一般是不是后面类的实例。
使用方法:if (对象名 instanceof 子类名称) {}

public class Demo02Instanceof {

    public static void main(String[] args) {


        giveMeAPet(new Dog());
    }

    public static void giveMeAPet(Animal animal) {
        // 判断一下父类引用animal本来是不是Dog
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;
            dog.watchHouse();
        }
        // 判断一下animal本来是不是Cat
        else if (animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
    }

}

ps:USB接口案例实现

public interface USB {

    public abstract void open(); // 打开设备

    public abstract void close(); // 关闭设备

}
**************************************************
// 鼠标就是一个USB设备
public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("打开鼠标");
    }

    @Override
    public void close() {
        System.out.println("关闭鼠标");
    }

    public void click() {
        System.out.println("鼠标点击");
    }
}
****************************************************
// 键盘就是一个USB设备
public class Keyboard implements USB {
    @Override
    public void open() {
        System.out.println("打开键盘");
    }

    @Override
    public void close() {
        System.out.println("关闭键盘");
    }

    public void type() {
        System.out.println("键盘输入");
    }
}

****************************************************
public class Computer {

    public void powerOn() {
        System.out.println("笔记本电脑开机");
    }

    public void powerOff() {
        System.out.println("笔记本电脑关机");
    }

    // 使用USB设备的方法,使用接口作为方法的参数
    public void useDevice(USB usb) {
        usb.open(); // 打开设备
        if (usb instanceof Mouse) { // 一定要先判断
            Mouse mouse = (Mouse) usb; // 向下转型
            mouse.click();
        } else if (usb instanceof Keyboard) { // 先判断
            Keyboard keyboard = (Keyboard) usb; // 向下转型
            keyboard.type();
        }
        usb.close(); // 关闭设备
    }

}
*******************************************************
public class DemoMain {

    public static void main(String[] args) {
        // 首先创建一个笔记本电脑
        Computer computer = new Computer();
        computer.powerOn();

        // 准备一个鼠标,供电脑使用
//        Mouse mouse = new Mouse();
        // 首先进行向上转型
        USB usbMouse = new Mouse(); // 多态写法
        // 参数是USB类型,我正好传递进去的就是USB鼠标
        computer.useDevice(usbMouse);

        // 创建一个USB键盘
        Keyboard keyboard = new Keyboard(); // 没有使用多态写法
        // 方法参数是USB类型,传递进去的是实现类对象
        computer.useDevice(keyboard); // 正确写法!也发生了向上转型
        // 使用子类对象,匿名对象,也可以
//        computer.useDevice(new Keyboard()); // 也是正确写法

        computer.powerOff();
        System.out.println("==================");

        method(10.0); // 正确写法,double --> double
        method(20); // 正确写法,int --> double
        int a = 30;
        method(a); // 正确写法,int --> double
    }

    public static void method(double num) {
        System.out.println(num);
    }

}

观察 DemoMain类得出,对于父类、子类都有的方法,以下几种方法都可以实现调用:

  1. 先进行向上转型,然后再传参
  2. 不向上转型,直接传实现类对象
  3. 使用子类匿名对象

final关键字

final关键字代表最终、不可改变的。

常见四种用法:
1. 可以用来修饰一个类

  • 当final关键字用来修饰一个类的时候,格式: public final class 类名称 {
    // … }

    含义:当前这个类不能有任何的子类,即不能使用一个final类来作为父类
    注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为子类。)

2. 可以用来修饰一个方法

  • 当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。 格式: 修饰符 final 返回值类型
    方法名称(参数列表) {
    // 方法体 }

    注意事项: 对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。
    3. 还可以用来修饰一个局部变量

  • 一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。

  • 对于基本类型来说,不可变说的是变量当中的数据不可改变
    对于引用类型来说,不可变说的是变量当中的地址值不可改变

        final Student stu2 = new Student("小何");
        System.out.println(stu2.getName()); // 小何
        stu2.setName("小何小何小何");
        System.out.println(stu2.getName()); // 小何小何小何

4. 还可以用来修饰一个成员变量

  • 对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变。

    1. 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
    2. 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
    3. 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。
上一篇:7. 类与对象3


下一篇:API--13--Objects类