方法的重写

重写:子类对父类中提供的方法进行重新定义

语法:子类和父类中的方法的声明(即方法名,参数列表,返回值类型)完全一致

重写又被称为方法的覆盖

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 方法对子类不可见

更多推荐