问题引导
- 使用传统的方法来解决(private 属性)
- 传统的方法带来的问题是什么? 如何解决?
问题是: 代码的复用性不高,而且不利于代码维护
解决方案: 引出我们要讲解的多态
多态的基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
多态的具体体现
方法的多态
重写和重载就体现多态
package com.hspedu.poly_;
/**
* @author:寰愬悏瓒�
* @date:2024/12/4 version:1.0
*/
public class PloyMethod {
public static void main(String[] args) {
// 方法重载体现多态
A a = new A();
// 传入不同的参数,就会调用不同的sum方法,就体现多态
System.out.println(a.sum(10,20));
System.out.println(a.sum(10,20,30));
// 方法重写体现多态
B b = new B();
a.say();
b.say();
}
}
class B {
public void say() {
System.out.println("B say()被调用....");
}
}
class A extends B {
public int sum(int n1,int n2) {
return n1 + n2;
}
public int sum(int n1,int n2,int n3) {
return n1 + n2 + n3;
}
public void say() {
System.out.println("A say()被调用....");
}
}
对象的多态
记住:
父类的引用 可以指向它子类的对象;
例子代码
Animal:
package com.hspedu.poly_.objectpoly_;
public class Animal {
public void cry() {
System.out.println("Animal cry() 动物在叫。。。");
}
}
Cat:
package com.hspedu.poly_.objectpoly_;
public class Cat extends Animal {
public void cry() {
System.out.println("Cat cry()小猫喵喵叫...");
}
}
Dog:
package com.hspedu.poly_.objectpoly_;
public class Dog extends Animal {
public void cry() {
System.out.println("Dog cry()小狗旺旺叫...");
}
}
PolyObject:
package com.hspedu.poly_.objectpoly_;
public class PolyObject {
public static void main(String[] args) {
// 体验对象多态特点
// animal 编译类型就是 Animal , 运行类型是 Dog
Animal animal = new Dog();
//因为运行时,这时候执行到改行时,animal运行类型是Dog,所以cry就是Dog的cry
animal.cry(); // 小狗旺旺叫
animal = new Cat();
animal.cry();// 小猫喵喵叫
}
}
使用多态的机制来解决主人喂食物的问题,走代码
多态注意事项和细节讨论
多态的向上转型
1.先编译后运行,在编译的时候看父类有没有这个方法有的 话,编译才能通过,但是后面 运行的时候还是就近原则,先看子类有没有,有的话就调用子类的
2.特有成员(是指父类没有,子类有的成员)
3.成员是指属性和方法
代码:
Animal类
package com.hspedu.poly_.detail_;
public class Animal {
String name = "动物";
int age = 10;
public void sleep() {
System.out.println("睡");
}
public void run() {
System.out.println("跑");
}
public void eat() {
System.out.println("吃");
}
public void show() {
System.out.println("Hello,你好");
}
}
Cat类
package com.hspedu.poly_.detail_;
public class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() { // Cat特有方法
System.out.println("猫抓老鼠");
}
}
PolyDatail类
package com.hspedu.poly_.detail_;
public class PolyDatail {
public static void main(String[] args) {
// 向上转型: 父类的引用指向了子类的对象
// 语法: 父类的类型引用名 = new 子类类型();
Animal animal = new Cat();
Object obj = new Cat(); //Object 也是 Cat的父类;
// 向上转型调用方法的规则如下:
// (1)可以调用父类中的所有成员(需遵守访问权限)
// (2)但是不能调用子类的特有成员(是指父类没有,子类有的方法)
// (3)因为在编译阶段,能调用哪些成员,是由编译类型来决定的
// animal.catchMouse(); 错误
// (4)最终运行效果 看子类(运行类型)的具体实现,即调用方法时,按照从子类(运行类型)开始查找方法,
// 然后调用,规则同前面讲的方法调用规则 一致。
animal.eat(); // 猫吃鱼
animal.show(); // Hello,您好
animal.sleep(); // 睡
animal.run(); // 跑
}
}
多态的向下转型
在
1.animal 现在的编译类型还是 Animal
2.强制类型转换只是将animal引用的对象视为Cat类,而不是真的将其转换为Cat类;
3.现在的 animal编译类型是:Animal,运行类型是:Cat
4.现在的 Cat编译类型是:Cat,运行类型是:Cat
修改 上述 PolyDatail类
// (4)最终运行效果 看子类(运行类型)的具体实现,即调用方法时,按照从子类(运行类型)开始查找方法,
// 然后调用,规则同前面讲的方法调用规则 一致。
animal.eat(); // 猫吃鱼
animal.show(); // Hello,您好
animal.sleep(); // 睡
animal.run(); // 跑
// 目的: 希望,可以调用Cat的 catchMouse();
// 多态的向下转型;
// (1)语法:子类类型 引用名 = (子类类型)父类引用;
// 问一个问题? cat 的编译类型是 Cat, 运行类型是 Cat
Cat cat = (Cat) animal;
cat.catchMouse(); //猫抓老鼠
// (2)要求父类的引用必须指向的是当前目标类型的对象;
}
}
属性没有重写之说!属性的值看编译类型
属性没有重写之说!属性的值看编译类型,方法看运行类型
package com.hspedu.poly_.detail_;
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);// true
System.out.println(aa instanceof BB);// true
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //父类
class BB extends AA {} // 子类
练习1
解析:
1.double不多介绍 了
2.double -> long 自动类型转换
3.int -> boolean 错误
4.String类是 Object的子类,当然 可以 向上/向下转型了
5.Integer就是int ,也是 Object的子类