方法覆盖

Posted yxc-160206

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方法覆盖相关的知识,希望对你有一定的参考价值。

方法覆盖

方法覆盖的概述

  • 方法覆盖又叫做:方法重写,英语单词叫做:Override、Overwrite,都可以。
  • 比较常见的叫法:方法覆盖、方法重写、Override。
  • 方法覆盖,就是将继承过来的那个方法给覆盖掉了。继承过来的方法没了。

方法覆盖的引入

public class OverrideTest {
    public static void main(String[] args) {
        Bird b = new Bird(); //创建鸟对象
        b.move(); //让鸟儿移动
    }
}

class Animal{ //父类
    public void move(){ //移动
        System.out.println("动物在移动!");
    }
}
class Bird extends Animal{ //子类
}

以上程序存在问题:

  • 鸟儿在执行move()方法的时候,最好输出的结果是:“鸟儿在飞翔”
  • 但是当前的程序在执行move()方法时输出的结果是:“动物在移动”
  • 很显然Bird子类从Animal父类中继承过来的move()已经无法满足业务的需求。

子类继承父类时,有一些“行为”可能不需要改进,有一些“行为”可能面临着必须改进。因为父类中继承过来的方法已经无法满足子类的业务需求。

方法覆盖的使用时机

  • 子类继承父类之后,当继承过来的方法无法满足当前子类的业务需求时,子类有权利对这个方法进行重新编写,有必要进行“方法的覆盖”。
public class OverrideTest {
    public static void main(String[] args) {
        Bird b = new Bird();
        b.move();

        Cat C = new Cat();
        C.move();
    }
}
class Animal{
    public void move(){
        System.out.println("动物在移动!");
    }
}
class Bird extends Animal{
    //对move()方法进行方法覆盖、方法重写
    //最好将父类中的方法原封不动的复制过来。(不建议手动编写)
    public void move(){
        System.out.println("鸟儿在飞翔!");
    }
}
class Cat extends Animal{
    public void move(){//方法重写
        System.out.println("猫在走猫步!");
    }
}

使用方法覆盖需满足的条件

  1. 两个类必须有继承关系
  2. 重写之后的方法和之前的方法具有:
    • 相同的返回值类型
    • 相同的方法名
    • 相同的形式参数列表
  3. 访问权限不能更低,可以更高。
  4. 重写之后的方法不能比之前的方法抛出更多的异常,可以更少。

方法覆盖的重要结论

  • 在子类对父类继承过来的方法进行“方法覆盖”之后,子类对象调用该方法的时候,一定执行覆盖之后的方法。

方法覆盖的注意事项

  • 方法覆盖只是针对方法,和属性无关。
  • 私有方法无法覆盖。
  • 构造方法不能被继承,所以构造方法也不能被覆盖。
  • 方法覆盖只是针对于实例方法,“静态方法覆盖”没有意义。
  • 总结两句话:私有不能覆盖,静态不谈覆盖。

方法覆盖注意事项的解读

静态方法不存在方法覆盖

  • 方法覆盖要和多态联合起来使用才有意义

    Animal a = new Cat();

    a.move();

    • 要的是什么结果?
      • 编译的时候move()方法是Animal
      • 运行的时候会自动调用子类重写move()方法上.
    • 假如没有多态机制,只有方法覆盖机制,会有意义吗?
      • 没有多态机制,方法覆盖也可以没有,如果父类方法无法满足子类业务需求时,子类完全可以定义一个全新的方法。
    • 方法覆盖和多态不能分开。
  • 静态方法存在方法覆盖吗?

    • 多态和对象有关,而静态方法的执行不需要对象,所以,一般情况下,我们会说静态方法“不存在”,不探讨静态方法的覆盖。
  • 方法覆盖只是针对“实例方法”,“静态方法覆盖”没有意义。

    • 这是因为方法覆盖和多态连用才有意义。
  • 在方法覆盖中,关于方法的返回值类型。

    • 在什么条件满足之后,会构成方法的覆盖?
      1. 发生具有继承关系的两个类之间。
      2. 父类中方法和子类重写之后的方法:
        • 具有相同的方法名
        • 相同的形式参数列表
        • 相同的返回值类型
    • 在学习多态机制之后:
      • “相同的返回值类型”可以修改一下吗?
        • 对于返回值类型是基本数据类型来说,必须一致
        • 对于返回值类型是引用数据类型来说,重写之后返回值类型可以变得更小。(但意义不大,实际开发中没有人这样写)

私有方法不能覆盖

  • 经过测试,私有方法不能覆盖,记住就行

    //私有方法不能覆盖
    public class OverrideTest05 {
        private void doSome(){//私有方法
            System.out.println("Override‘s private method doSome execute!");
        }
    
        public static void main(String[] args) {
            OverrideTest05 ot = new T();
            ot.doSome();//Override‘s private method doSome execute!
        }
    
    }
    class T extends OverrideTest05{
        //尝试重写父类中doSome()方法
        //访问权限不能更低,可以更高
        public void doSome(){
            System.out.println("T‘s public doSome method execute!");
        }
    }
    

方法覆盖的经典案例

  • 注意:方法覆盖/重写的时候,建议将父类的方法复制粘贴,这样比较保险。
public class OverrideTest03 {
    public static void main(String[] args) {
        ChinaPeople p1 = new ChinaPeople();//创建中国人对象
        p1.setName("张三");
        p1.speak();

        AmericPeople p2 = new AmericPeople();//创建美国人对象
        p2.setName("Jack");
        p2.speak();
    }
}

class People {
    private String name;

    public People() {
    }

    public People(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void speak() {
        System.out.println(name + "正在说话!");
    }
}

class ChinaPeople extends People {//中国人

    //中国人说汉语
    //所以子类需要对父类的speak()方法进行重写
    public void speak() {
        System.out.println(this.getName() + "正在说汉语!");
    }
}

class AmericPeople extends People {//美国人
    //美国人说汉语
    //所以子类需要对父类的speak()方法进行重写
    public void speak() {
        System.out.println(this.getName() + " speak English!");
    }
}

覆盖0bject类中的toString()方法

关于toString()方法的作用是什么?

  • 作用:将“Java对象”转换成“字符串的形式”。

Object类中toString()方法的默认实现是什么?

public String toString(){
    return getClass().getName() + "@" +Interger.toHexString(hashCode());
}

toString:方法名的意思是转换成String。含义:调用一个java对象的toString()方法就可以将该java对象转换成字符串的表示。

toString()方法存在的作用就是:将java对象转换成字符串形式。

大多数的javatoString()方法都是需要覆盖的。因为Object类中提供的toString()方法输出的是一个java对象的内存地址。

至于toString()方法具体怎么进行覆盖?

  • 格式可以自定义,或者听需求的。(听项目要求的)

toString()方法给的默认实现够用吗?

public class OverrideTest04 {
    public static void main(String[] args) {
        MyDate t1 = new MyDate();//创建一个日期对象
        //调用toString()方法(将对象转换成字符串形式)
        //对这个输出结果不满意!希望输出:xxxx年xx月xx日
        //重写MyDate的toString()方法之前的结果
        //System.out.println(t1.toString());//MyDate@75412c2f

        //重写MyDate的toString()方法之前的结果
        System.out.println(t1.toString());//1970年1月1日
        //当直接输出一个“引用”的时候,println()方法会先自动调用"引用.toString()",
        // 然后输出toString()方法的执行结果。
        System.out.println(t1);//1970年1月1日
    }
}

class MyDate {
    private int year;
    private int month;
    private int day;

    public MyDate() {
        this(1970, 1, 1);
    }

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    //从Object类中继承过来的那个toString()方法已经无法满足业务需求了
    //在子类MyDate中有必要对父类的toString()方法进行覆盖/重写
    //现在的业务要求是:调用toString()方法进行字符串转换的时候,
    //希望转换的结果是:xxxx年xx月xx日,这种格式。
    //重写一定要复制粘贴,不要手动编写,会错的
    public String toString() {
        return year + "年" + month + "月" + day + "日";
    }
}

回顾方法重载(overload)

方法重载的使用时机

  • 当在一个类当中,如果功能相似的话,建议将名字定义的一样,这样代码美观,并且方便编程。

使用方法重载需要满足的条件

  1. 在同一个类当中;
  2. 方法名相同;
  3. 参数列表不同(个数、顺序、类型)

方法重载和方法覆盖区别

  • 方法重载发生在同一个类当中;方法覆盖发生在具有继承关系的父子类当中。
  • 方法重载是一个类中,方法名相同,参数列表不同;
  • 方法覆盖是具有继承关系的父子类,并且重写之后的方法必须和之前的方法一致:方法名一致、参数列表一致、返回值类型一致。

以上是关于方法覆盖的主要内容,如果未能解决你的问题,请参考以下文章

Android片段z-index覆盖

如何覆盖继承的嵌套类中存在的虚拟方法

我可以在不放入 Activity 的情况下覆盖/处理片段中的 keyDown 吗?

从父片段到选项卡片段的接口侦听器不起作用

覆盖javascript以消除闪烁

覆盖一个常见的片段帮助其他标签片段