文章目录
什么是多态?
定义: 是指同一行为,具有多个不同表现形式。
多态的体现
父类名称 变量名 = 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类得出,对于父类、子类都有的方法,以下几种方法都可以实现调用:
- 先进行向上转型,然后再传参
- 不向上转型,直接传实现类对象
- 使用子类匿名对象
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关键字修饰,那么这个变量也照样是不可变。
- 由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
- 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
- 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。