一、多态概述
引入
多态是继封装、继承之后,面向对象的第三大特性。
生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也
是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
定义
多态是指同一行为,具有多个不同表现形式。
前提【重点】
1.
继承或者实现【二选一】
2.
方法的重写【意义体现:不重写,无意义】
3.
父类引用指向子类对象【格式体现】
二、多态的体现
代码中体现多态性:父类引用 指向 子类对象
多态格式:
父类名称 对象名 = new 子类名称();
或者
接口名称 对象名 = new 实现类名称();
代码实现
创建父类
public class Fu {
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有方法");
}
}
创建子类
public class Zi extends Fu{
@Override
public void method() {
System.out.println("父类方法重写)");
}
}
测试类
public class Demo01Multi {
public static void main(String[] args) {
//多态: 父类名称 对象名 = new 子类名称();
//左侧父类引用,右侧子类对象
Fu obj = new Zi();
//调用父类方法,实际是子类重写后的
obj.method();
//调用父类特有方法
obj.methodFu();
}
}
运行结果
父类方法重写)
父类特有方法
Process finished with exit code 0
三、多态访问成员变量和方法
访问成员变量的两种方式:
1. 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。
2. 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。
上代码
创建父类
public class Fu {
int num = 10;
public void showNum(){
System.out.println(num);
}
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有方法");
}
}
创建子类
public class Zi extends Fu{
int num = 20;
int age = 30;
@Override
public void method() {
System.out.println("子类方法");
}
@Override
public void showNum() {
System.out.println(num);
}
public void methodZi() {
System.out.println("子类特有方法");
}
}
创建测试类访问成员变量
public class Demo01MultiField {
public static void main(String[] args) {
Fu obj = new Zi();
//子类不能覆盖重写父类的成员变量
//直接通过对象名访问成员变量,等号左边是谁,就优先用谁,没有向上找
System.out.println(obj.num);//10
//父类成员变量没有,子类有不能访问。错误写法
// System.out.println(obj.age);
System.out.println("============");
//间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。
obj.showNum();//10 覆盖重写前
obj.showNum();//20 覆盖重写后
}
}
创建测试类访问成员方法
public class Demo02MultiField {
public static void main(String[] args) {
//多态
Fu obj = new Zi();
//编译看左,运行看右
obj.method();//父子都有,优先用子
obj.methodFu();//父有子没有,向上找父类
// obj.methodZi(); 编译看左,左边父类没有这个方法
}
}
四、多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展
性与便利。
五、引用类型转换
多态的转型分为向上转型与向下转型两种:
向上转型
向上转型
:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型。
使用格式:
父类类型 变量名
=
new
子类类型
();
如:
Animal a
=
new
Cat
();
向下转型
向下转型
:父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:
子类类型 变量名
=
(
子类类型
)
父类变量名
;
如
:
Cat c
=
(
Cat
)
a
;
上代码
创建父类:
public abstract class Animal {
public abstract void eat();
}
创建子类1:
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void play(){
System.out.println("特有方法:猫抓老鼠");
}
}
创建子类2:
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃肉");
}
public void play(){
System.out.println("汪汪汪");
}
}
创建测试类1:
/*
向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:
对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
解决方案:用对象的向下转型【还原】。
*/
public class Demo01Main {
public static void main(String[] args) {
//向上转型就是父类引用指向子类对象
Animal animal = new Cat();//本来创建的时候是一只猫
animal.eat();
// animal.play();//错误写法
//向下转型,类似于强制类型转换
//格式: 子类名称 新对象名 = (子类名称)老对象名
Cat cat = (Cat)animal;
//这时可以调用子类特有方法
cat.play();//特有方法:猫抓老鼠
//错误的向下转型
Dog dog = (Dog)animal;//此处未报错
//dog.eat();//运行时出现异常:ClassCastException:类转换异常
}
}
创建测试类2:
/*
如何才能知道一个父类引用的对象,本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。
*/
public class Demo02Instanteof {
public static void main(String[] args) {
//向上转型
Animal animal = new Cat();
// Animal animal = new Dog();
//向下转型
//判断这个动物是猫是狗
//如果是狗就转换成狗
if(animal instanceof Dog){
System.out.println("这个动物是狗");
Dog dog = (Dog)animal;
dog.eat();
dog.play();
}
else if(animal instanceof Cat){
System.out.println("这个动物是猫");
Cat cat = (Cat)animal;
cat.eat();
cat.play();
}
sendAnimal(animal);
}
public static void sendAnimal(Animal animal){
//向下转型
//判断这个动物是猫是狗
//如果是狗就转换成狗
if(animal instanceof Dog){
System.out.println("这个动物是狗");
Dog dog = (Dog)animal;
dog.eat();
dog.play();
}
else if(animal instanceof Cat){
System.out.println("这个动物是猫");
Cat cat = (Cat)animal;
cat.eat();
cat.play();
}
}
}
六、接口,多态的综合案例:笔记本电脑
笔记本电脑:
笔记本电脑(
laptop
)通常具备使用
USB
设备的功能。在生产时,笔记本都预留了可以插入
USB
设备的
USB
接口,
但具体是什么
USB
设备,笔记本厂商并不关心,只要符合
USB
规格的设备都可以。
定义
USB
接口,具备最基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守
USB
规范,实现
USB
接口,否则鼠标和键盘的生产出来也无法使用。
案例分析:
进行描述笔记本类,实现笔记本使用
USB
鼠标、
USB
键盘
USB
接口,包含开启功能、关闭功能
笔记本类,包含运行功能、关机功能、使用
USB
设备功能
鼠标类,要实现
USB
接口,并具备点击的方法
键盘类,要实现
USB
接口,具备敲击的方法
图例:
![](https://i-blog.csdnimg.cn/blog_migrate/a53c47e51c5a2ef120069db23fb05b63.png)
代码实现:
创建USB接口
public interface USB {
public abstract void open();
public abstract void close();
}
创建鼠标类
public class Mouse implements USB{
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
public void play2(){
System.out.println("点击鼠标");
}
}
创建键盘类
public class Keyboard implements USB{
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
public void play1(){
System.out.println("键盘输入");
}
}
创建电脑类
public class Computer {
public void putOn(){//打开电脑
System.out.println("开机");
}
public void putOff(){//关闭电脑
System.out.println("关机");
}
public void usbMain(USB usb){//使用USB的方法
usb.open();
if(usb instanceof Keyboard){
Keyboard keyboard = (Keyboard) usb;
keyboard.play1();
}
else if(usb instanceof Mouse){
Mouse mouse = (Mouse) usb;
mouse.play2();
}
usb.close();
}
}
创建测试类
public class DemoMain {
public static void main(String[] args) {
//创建电脑
Computer computer = new Computer();
//打开电脑
computer.putOn();
//准备鼠标供电脑使用
// Mouse mouse = new Mouse();
// USB usb = mouse;
//或者
USB usb = new Mouse();
// usb.open();
computer.usbMain(usb);
//创建一个键盘
Keyboard keyboard = new Keyboard();
computer.usbMain(keyboard);
//关闭电脑
computer.putOff();
}
}
本篇完结,有喜欢的小伙伴我们可以一起交流讨论技术问题。谢谢支持!