Java 4——方法的重写 多态
·
方法的重写
重写:子类对父类中提供的方法进行重新定义
语法:子类和父类中的方法的声明(即方法名,参数列表,返回值类型)完全一致
重写又被称为方法的覆盖
public class LiYuan {
public void makeCountry(){
System.out.println("李渊想建立一个自己的国家");
}
}
public class LiShiMing extends LiYuan{
//子类中的方法必须和父类中的方法完全一致
public void makeCountry(){
//半盖
super.makeCountry();//super可以调用父类中被重写了的内容
System.out.println("李世明也想建立一个自己的国家");
}
public static void main(String[] args) {
LiShiMing l = new LiShiMing();
l.makeCountry();
}
}
/*输出:
李渊想建立一个自己的国家
李世明也想建立一个自己的国家
*/
规则
| 规则 | 说明 |
|---|---|
| 方法签名必须相同 | 方法名 + 参数列表(顺序、个数、类型)完全一致 |
| 返回值类型可以更小 | 允许返回父类返回类型的子类(称为协变返回类型,JDK 1.5+) |
| 访问权限不能更严格 | 父类 public → 子类只能是 public;父类 protected → 子类可以是 protected 或 public |
不能重写 private 方法 |
private 方法在子类中不可见,无法重写(但可以定义同名方法,那是一个新方法) |
不能重写 final 方法 |
被 final 修饰的方法不能被重写 |
不能重写 static 方法 |
静态方法属于类,不存在重写(子类可以定义同名静态方法,称为“隐藏”) |
| 不能抛出比父类更宽泛的异常 | 子类方法抛出的异常类型必须是父类方法抛出异常的子类或相同 |
重写vs重载
| 比较项 | 重写(Override) | 重载(Overload) |
|---|---|---|
| 发生范围 | 子类与父类之间 | 同一个类中 |
| 方法名 | 必须相同 | 必须相同 |
| 参数列表 | 必须相同 | 必须不同(个数、类型、顺序) |
| 返回值 | 相同或协变 | 可以不同 |
| 修饰符 | 不能更严格 | 无限制 |
| 异常 | 不能抛出更宽泛的异常 | 无限制 |
| 静态方法 | 不能被重写(只能隐藏) | 可以重载 |
多态
多态:同一个对象拥有多种形态,是面向对象编程的三大特性之一(封装、继承、多态)。它允许同一个行为具有多个不同表现形式,或者说一个接口,多种实现。
前提条件
1.继承关系(或接口实现)
2.方法重写(子类重写父类的方法)
3.父类引用指向子类对象
Animal a = new Dog(); // 父类引用指向子类对象
a.sound(); // 调用的是 Dog 的 sound()
作用:把不同的数据类型进行统一,让程序具有超强的可拓展性
//猫是一种懂动物
public class Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
//猫是一种动物 -> 继承关系
//可以把猫当成动物来看
public class Cat extends Animal{
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
}
public class Person {
// public void feedCat(Cat c) {
// c.eat();
// }
// public void feedDog(Dog d) {
// d.eat();
// }
// public void feedDaXiang(DaXiang dx) {
// dx.eat();
// }
public void feed(Animal ani) { //接收到的所有动物都是animal
ani.eat();
}
}
public class Client {
public static void main(String[] args) {
// Cat c = new Cat();
// Dog d = new Dog();
// Person p = new Person();
// p.feedCat(c);
// p.feedDog(d);
//Cat c = new Cat();//创建一只猫
Animal ani1 = new Cat();//可以把猫当成动物来看,把子类的对象赋值给父类的引用(变量) 向上转型
Animal ani2 = new Dog();
Animal ani3 = new DaXiang();
Person p = new Person();
p.feed(ani1);
p.feed(ani2);
p.feed(ani3);
//多态:把不同的数据类型进行统一
}
}
多态的两种形式
| 形式 | 示例 |
|---|---|
| 基于继承的多态 | Parent p = new Child(); |
| 基于接口的多态 | List list = new ArrayList(); |
多态中的成员访问
| 成员类型 | 编译看左边(父类) | 运行看右边(子类) |
|---|---|---|
| 成员变量 | ✅ 父类变量 | ❌ 子类变量不可见 |
| 成员方法 | 父类声明的方法 | ✅ 子类重写的方法 |
| 静态方法 | 父类方法(不存在重写) | 父类方法 |
向上转型&向下转型
把子类的对象赋值给父类的变量 -> 向上转型(缺点:屏蔽掉子类中特有的方法)
把父类的变量转化回子类的变量 -> 向下转型(向下转型有可能会有风险 Java要求必须要写强制类型转换)(格式:(转换之后的数据类型)变量)
//猫是一种懂动物
public class Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
//猫是一种动物 -> 继承关系
//可以把猫当成动物来看
public class Cat extends Animal{
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫喜欢抓老鼠");
}
}
public class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
}
public class Person {
// public void feedCat(Cat c) {
// c.eat();
// }
// public void feedDog(Dog d) {
// d.eat();
// }
// public void feedDaXiang(DaXiang dx) {
// dx.eat();
// }
public void feed(Animal ani) { //接收到的所有动物都是animal
ani.eat();
}
}
public class Client {
public static void main(String[] args) {
// Cat c = new Cat();
// Dog d = new Dog();
// Person p = new Person();
// p.feedCat(c);
// p.feedDog(d);
//Cat c = new Cat();//创建一只猫
Animal ani1 = new Cat();//可以把猫当成动物来看,把子类的对象赋值给父类的引用(变量) 向上转型 但是向上转型会屏蔽掉子类中特有的方法
Animal ani2 = new Dog();
Animal ani3 = new DaXiang();
// Person p = new Person();
// p.feed(ani1);
// p.feed(ani2);
// p.feed(ani3);
//多态:把不同的数据类型进行统一
//向下转型
Cat cc = (Cat)ani1;
cc.catchMouse();//猫又可以抓老鼠了
}
}
多态与重写、重载的关系
| 概念 | 关系 |
|---|---|
| 多态 + 重写 | 动态绑定,运行时决定调用哪个方法(多态的核心机制) |
| 多态 + 重载 | 重载是编译时决定(静态多态),属于早期绑定,不是真正的多态 |
应用场景
1.方法参数:接收父类类型,传入任意子类对象。
2.返回值:返回父类类型,实际返回子类对象。
3.数组/集合:存储父类类型的元素,实际放入子类对象。
// 集合多态
List<Animal> list = new ArrayList<>();
list.add(new Dog());
list.add(new Cat());
误区
| 误区 | 正确理解 |
|---|---|
| 父类引用不能调用子类新增方法 | 是的,需要向下转型才能调用 |
| 成员变量也具有多态 | 错误,成员变量没有多态,编译看左边 |
| 静态方法可以被重写从而实现多态 | 错误,静态方法不能被重写,没有多态 |
private 方法可以被重写 |
错误,private 方法对子类不可见 |
更多推荐
所有评论(0)