【java基础18:方法覆盖与多态】什么时候使用方法覆盖 toString方法的覆盖 多态的基础语法与作用 向上/向下转型

本文详细讲解了方法覆盖(Override)的概念、何时使用以及注意事项,包括方法重写规则和多态的实现、基础语法和实例,以及多态在降低耦合度和提高扩展性中的作用。还介绍了面向对象的三大特征和软件开发原则,通过实例演示了如何在编程中应用这些概念。
摘要由CSDN通过智能技术生成

目录

方法覆盖Override

多态


方法覆盖Override

  1. 方法覆盖初体验,什么样的程序要方法覆盖

    /*
        当前程序存在的问题(设计上的问题)??
            鸟儿在执行move()方法的时候,最好输出的结果是:“鸟儿在飞翔”
            但是当前的程序在执行move()方法时输出的结果是:动物在移动
     */
    public class OverrideTest01 {
        public static void main(String[] args){
            //创建鸟儿对象
            Bird b = new Bird();
            //让鸟儿动
            b.move();
    
            //创建一个猫
            Cat1 c = new Cat1();
            //让猫动
            c.move();
        }
    }
    //父类
    class Animal1{
    
        //可能这个方法不需要改动
        public void doSome(){
    
        }
        //而这个方法需要改动。
        //移动
        public void move(){
            System.out.println("动物在移动!");
        }
    }
    //子类
    class Bird extends Animal1{
        //子类继承父类后,有一些“行为”可能不需要改进,而有一些“行为”必须改进
        //因为父类中继承过来的方法已经无法满足子类的业务需求。
    
        //鸟儿在移动的时候要输出:鸟儿在飞翔!!
    }
    class Cat1 extends Animal1{
        //猫在移动时希望输出:喵喵在走猫步!!
    
    }
    
    
  2. 什么时候构成方法覆盖以及注意事项

    /*
    
        回顾一下方法重载:
            什么时候考虑使用方法重载Overload?
                在一个类中,几个方法功能相似时,建议将方法名同名,这样代码美观,又方便编程
            满足什么条件时构成方法重载?
            1、同一个类中
            2、方法名相同
            3、参数列表不同	(个数/顺序/类型 不同,都算不同)
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
        什么时候我们会考虑使用“方法覆盖”?
            子类继承父类之后,继承过来的方法无法满足当前子类的业务需求时,子类有权对这个方法进行重写
            有必要进行“方法的覆盖”
    
        方法覆盖又叫:方法重写(重新编写)、英:Override、Overwrite
        比较常见的:方法覆盖、方法重写、override。
    
         重要结论:
            当子类对父类继承过来的方法进行“方法覆盖”之后,子类调用该方法时,执行覆盖之后的方法
    
        什么情况构成方法覆盖
            1、两个类必须要有继承关系
            2、两个方法必须有:
                  相同的返回值类型
                  相同的方法名
                  相同的形式参数列表
            3、访问权限不能更低,可以更高。
            4、重写之后的方法不能比之前的方法抛出更多的异常,可以更少。
    
        注意事项:
            1、方法覆盖只是针对方法,与属性无关。
            2、私有方法无法覆盖
            3、构造方法不能继承,所以构造方法也不能被覆盖
            4、方法覆盖只是针对“实例方法”,“静态方法”的覆盖没有意义
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- - - - - - 
            方法重载和方法覆盖有什么区别?
                1、方法重载发生在同一个类中
                2、方法覆盖是发生在具有继承关系的父类与子类之间
                3、方法重载是在同一个类中,方法名相同,参数列表不同。
                4、方法覆盖是具有继承关系的父子类,并且重写之后的方法必须和之前的方法一致:
                    方法名、参数列表 以及 返回值类型的一致。
    
     */
    public class OverrideTest02 {
        public static void main(String[] args){
    
            Animal2 a = new Animal2();
            a.move();
    
            Bird2 b = new Bird2();
            b.move();
    
            Cat2 c = new Cat2();
            c.move();
    
            //这两个方法不构成覆盖,构成重载
            c.sing();
            c.sing(100);
        }
    }
    class Animal2{
    //    public void move(){
    //        System.out.println("动物在移动");
    //    }
    
        //如果原来是protected,则不会报错
        protected void move(){
            System.out.println("动物在移动");
        }
    
        public void sing(int sing){
            System.out.println("动物在嚎叫");
        }
    }
    class Bird2 extends Animal2{
        //对move方法进行方法覆盖
        //最好的方法是将原方法直接复制过来,然后修改。
        //是将原来的方法覆盖掉了,继承过来的方法跟被注释掉一样。
        public void move(){
            System.out.println("bird在飞翔!");
        }
    
        //protected 表示受保护的,没有public开放
        /*      3
        错误: Bird2中的sing(int)无法覆盖Animal2中的sing(int)
          正在尝试分配更低的访问权限; 以前为public
        protected void sing(int s){
            System.out.println("喵");
        }
         */
    }
    class Cat2 extends Animal2{
        public void move(){
            System.out.println("喵喵走猫步!");
        }
    
        //此方法与父类中sing(int sing)有没有构成方法覆盖?
        //没有,因为这是两个不同的方法,因为他们的参数列表不同
        //但是此方法构成方法重载,原因:子类继承父类,父类中的所有都相当于复制了一份到子类中,可以算是在同一个类中
        //这两个方法名字相同,参数列表不同,所以构成重载
        public void sing(){
            System.out.println("喵喵喵");
        }
    
        /* 	4、
            错误: Cat2中的move()无法覆盖Animal2中的move()
            被覆盖的方法未抛出java.lang.Exception
            错误:未报告的异常错误java.lang.Exception; 必须对其进行捕获或声明以便抛出
    
            public void move()throws Exception{
                System.out.println("喵喵走猫步!");
            }
        */
    }
    
    
  3. 方法覆盖实例

    /*
        方法覆盖案例
         注意:方法覆盖/重写时,建议将父类的方法复制过来再修改
               原因:可能方法名的某个字母大写/写错,就不会发生方法覆盖了,还是调用原来的方法
                     不好找到错误,可能你会以为是其他问题,找了半天发现名字错了,解决这种问题浪费时间
     */
    public class OverrideTest03 {
        public static void main(String[] args){
            //这里错误:没有在子类中提供有参数的构造方法
            //Chinese cp = new Chinese("zhong");
            //这里可以,因为默认提供无参的构造方法
            Chinese2 cp = new Chinese2();
            cp.setName("张三");
            cp.speak();
    
            American ap = new American();
            ap.setName("Jack");
            ap.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 Chinese2 extends People{
        //中国人说中国话,进行方法重写
        public void speak(){
            //这里是子类访问父类中的私有例变量name ,要用方法调用。
            //System.out.println(name +"bb....");
            //this.表示当前对象,可以省。不省比较好。
            System.out.println(this.getName() +"逼逼叨叨....");
        }
    
    }
    
    class American extends People{
        //美国人说英语,进行方法重写
        public void speak(){
            System.out.println(this.getName() +"bb....");
        }
    }
    
  4. toString()的方法覆盖

    /*
        大多数的toSting方法都是需要覆盖的。因为Object中提供的toString()方法输出的是一个对象的内存地址
        进行覆盖的格式可以自定义,或者看项目需求。
    
        关于Object中的toString()方法
            1、toString()方法的作用是什么?
                作用:将“java”对象转换成“字符串”的形式
    
            2、Object类中toString()方法的默认实现是什么?
                  public String toString() {
                      return getClass().getName() + "@" + Integer.toHexString(hashCode());
                  }
    
               toString  方法名的意思:转换成String
               含义:调用一个java对象的toString()方法就可以将该java对象转换成字符串的表示形式
    
            3、 那么toString()方法的默认实现够用吗?
     */
    public class OverrideTest04 {
        public static void main(String[] args){
            //创建日期对象
            MyDate md = new MyDate();
            //调用toString()方法(将对象转换成字符串形式)
            //System.out.println(md.toString());      //MyDate@1b6d3586
            //问:对这个输出结果满不满意?     答:不满意   理想输出:xxxx年xx月xx日
            //当父类中的Object方法中提供的toString()方法不满足需求时,需要进行方法覆盖。
    
            //重写后
    
            System.out.println(md.toString());      //1999年9月9日
            //当输出一个“引用”时,println会自动调用该引用的toString()方法
            System.out.println(md);     //1999年9月9日
    
            MyDate md2 = new MyDate(2000,11,11);
            System.out.println(md2);    //2000年11月11日
    
    
            //创建一个学生对象
            Student7 s = new Student7(110,"张三");
            //重写之前
            //System.out.println(s.toString());   //Student7@1b6d3586
            //输出一个对象之后,可能更愿意看到学生的信息,而不是这个学生对象的内存地址,此时对它进行重写
            //重写之后
            System.out.println(s.toString());     //学号为110的学生名字:张三
    
        }
    }
    
    class MyDate{
        private int year;
        private int month;
        private int day;
    
        public MyDate(){
            this(1999,9,9);
        }
        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;
        }
    
        //在子类中对不满足需求的toString()这个父类继承过来的方法进行覆盖
        //要求:调用toString方法的时候输出:xxxx年xx月xx日
        //重写时一定要复制粘贴,不能手动写,可能会错。
        public String toString(){
            return year + "年" + month + "月" + day + "日";
        }
    }
    
    class Student7{
        int no;
        String name;
        public Student7(){
    
        }
        public Student7(int no,String name){
            this.no = no;
            this.name = name;
        }
        //重写
        public String toString(){
            return "学号为" + no + "的学生名字:" + name ;
        }
    }
    
    

多态

  1. 多态的基础语法

    向上/向下转型 ,多态是什么,什么时候使用向下转型

    在这里插入图片描述

    //父类:动物类
    public class Animal3 {
        public void move(){
            System.out.println("动物在移动");
        }
    }
    
    //子类:猫类
    public class Cat3 extends Animal3{
        //重写
        public void move(){
            System.out.println("猫在走猫步");
        }
        //猫除了move外,还有自己特有的行为,比如:抓老鼠
        public void catchMouse(){
            System.out.println("猫正在抓老鼠");
        }
    }
    
    //子类:鸟儿类
    public class Bird3 extends Animal3{
        public void move(){
            System.out.println("鸟儿在空中闪现");
        }
        public void sing(){
            System.out.println("鸟儿在唱歌!");
        }
    }
    
    //不继承Animal3
    public class Dog3 {
        public void move(){
            System.out.println("狗在疾跑");
        }
    }
    
    /*
        多态的基础语法:
            1、学习多态基础语法之前,我们需要普及两个概念:
                   第一: 向上转型(upcasting)
                       子 ---- > 父  (类似于:自动类型转换)
                       Animal a = new Cat();
                   第二: 向下转型(downcasting)
                       父 ---- > 子  (类似于:强制类型转换,需要加强制类型转换符)
            注意:
                ★重点★:无论是向上/向下转型,两个类之间必须有继承关系,没有继承关系编译器会报错。
                1、java中允许 向上转型,也允许 向下转型
                2、引用类型转换包括 :向上转型、向下转型。与基本数据类型的自动/强制类型转换 原理相似。
                但引用类型没有 自动类型转化/强制类型转换这种说法   因为 自动/强制类型转换 是用于基本数据类型的
    
            2、多态是指:
                   父类型“引用”指向 子类型“对象”
                   包括:编译阶段、运行阶段
                   编译阶段:静态绑定父类的方法       运行阶段:动态绑定子类对象的方法。
            3、什么时候必须使用“向下转型”?
                   不能随便向下转型。
                   当你需要访问的是子类对象中“特有”的方法时,必须进行向下转型。
     */
    
    public class Test01 {
        public static void main(String[] args){
    
            Animal3 a1 = new Animal3();
            a1.move();  //动物在移动
            Bird3 b1 = new Bird3();
            b1.move();  //鸟儿在空中闪现
            Cat3 c1 = new Cat3();
            c1.move();  //猫在走猫步
    
            /*可以这样写吗?
                1、Animal3 和 Cat3 之间有继承关系吗?  有的
                2、Animal3 是父类 , Cat3是子类。
                3、Cat is a Animal  这句话可以说通。
                4、经过测试得知java中支持这样的语法:   父类的引用 允许指向 子类的对象。
                    Animal3 a2 = new Bird3();
                    a2就是父类型的引用      new Bird3()  是创建了一个子类型的对象
                    允许a2这个父类的引用 指向 Bird3()的对象
             */
            Animal3 a2 = new Bird3();
            Animal3 a3 = new Cat3();
    
            //没有继承关系的两个类型之间不存在转型
            //错误:不兼容的类型: Dog3无法转换为Animal3
            //Animal3 ad = new Dog3();
    
            //调用a2与a3的move()方法。
    /*
    什么是多态?
    	多种形态,多种状态
    分析:a2.move();
    
    java程序分为编译阶段和运行阶段
    - 编译阶段(属于静态绑定):
      对于编译器来说,编译器只知道a2的类型是Animal3。
      所以检查语法时会去Animal3中找move()方法,找到后绑定move()方法,编译通过后,静态绑定成功
    
    - 运行阶段(属于动态绑定):
      运行阶段,实际上是堆内存中创建的java对象是Cat3对象,所以move()的时候,真正参与move的对象是一个cat,所以运行阶段会动态执行Cat3对象的move方法。
    
    多态表示多种形态:编译时一种形态、运行时一种形态。
    */
            a2.move();      //鸟儿在空中闪现
            a3.move();      //猫在走猫步
    
            //= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            Animal3 a5 = new Cat3();   //底层对象是一只猫
            //a5.catchMouse();
            /*	分析能否编译和运行?
                分析程序一定要分析编译阶段的静态绑定和运行阶段的动态绑定
                只有编译动过的代码才能运行,编译不通过,根本没有运行的机会
                错误: java: 找不到符号      符号:   方法 catchMouse()      位置: 类型为Animal3的变量 a5
                原因: 编译器只知道a5的类型是Animal3,去Animal3.class文件中查找catchMouse()方法时,发现没有该方法,所以静态绑定失败,编译报错,无法运行(语法不通过)
            */
    
            //假设进行到这里,必须要调用catchMouse()方法,应该怎么操作?
            //这时就必须使用“向下转型”了。
    
            //以下代码编译通过
            //a5是Animal3类型,转成Cat,Animal3和Cat3之间存在继承关系,所以编译通过。
            Cat3 x = (Cat3)a5;
            x.catchMouse(); //猫正在抓老鼠
    
            //向下转型有风险吗? 有
            Animal3 a6 = new Bird3();  //表面上(编译时)a6是一个Animal3对象,运行时实际上是一个鸟儿
            /*
                分析以下程序:编译报错还是运行报错?
                Cat3 y = (Cat3)a6;
                y.catchMouse();
                    编译阶段:编译器检测到a6这个引用是Animal3类型,而Animal3与Cat3之间存在继承关系
                           可以向下转型,编译通过。
    
                    运行阶段:堆内存实际创建的对象是:Bird3对象,实际运行时,Bird3对象转换成Cat3对象
                            就会报错,因为Bird3与Cat3之间没有继承关系。
    
                运行时出现错误:    java.lang.ClassCastException    类型转换异常。
                    ★这个异常非常经典、非常重要.
             */
    
            /*
                怎么避免ClassCastException异常的发生?
    
                新的内容:
                    instanceof (运行阶段动态判断)
                1、instanceof 可以在运行阶段动态判断引用指向的对象的类型。
                2、instanceof 语法:
                      (引用 instanceof 类型)
                3、instanceof运算符的运算结果只能是:true/false
                4、c是一个引用,c变量保存了内存地址指向了堆中的对象。
                    假设(c instanceof Cat) 为true
                        c引用指向的堆内存中的java对象是一个Cat
                    假设(c instanceof Cat) 为false
                        c引用指向的堆内存中的java对象不是一个Cat。
             */
            System.out.println(a6 instanceof Cat3); //false
            if(a6 instanceof Cat3){//如果a6是Cat3类型的,才会执行向下转型
                Cat3 y = (Cat3)a6;  //a6是Cat3的对象,才会执行。如果不是则不执行。
                y.catchMouse();
            }
        }
    }
    

    向下转型必须使用instanceof进行判断的原因。

    public class AnimalTest {
        //Test方法是程序员B编写
        //这个Test()方法的参数是一个animal
        public void Test(Animal3 a){
            //这个方法别人会去调用
            //别人调用的时候可能会穿过来bird/cat,我们不知道他调用时会传一个什么进来。
            //所以用instanceof判断之后就能很好的调用子类特有的方法。防止类型转换异常的出现。
            if(a instanceof Cat3){
                Cat3 c = (Cat3)a;
                c.catchMouse();
            }else if(a instanceof Bird3){
                Bird3 b =(Bird3)a;
                b.sing();
            }
        }
    }
    
    /*
    	疑问:
            可以看到底层是new Bird3()/new Cat3()!,为什么还要使用instanceof进行判断?
        原因:
            以后可能看不到。
    */
    public class Test02 {
        public static void main(String[] args){
            Animal3 ab = new Bird3();
            Animal3 ac = new Cat3();
    
            if(ab instanceof Bird3){
                Bird3 b = (Bird3)ab;
                b.sing();
            }else if(ab instanceof Cat3){
                Cat3 c =(Cat3)ab;
                c.catchMouse();
            }
    
            if(ac instanceof Bird3){
                Bird3 b = (Bird3)ac;
                b.sing();
            }else if(ac instanceof Cat3){
                Cat3 c =(Cat3)ac;
                c.catchMouse();
            }
    
            //这里程序员A负责编写
            AnimalTest at = new AnimalTest();
            at.Test(new Cat3());
            at.Test(new Bird3());
        }
    }
    
  2. ※★多态在开发中的作用★※

    多态在开发中的作用是:降低耦合度,提高程序的扩展力。

    public class Master{
    	public void feed(Dog d){
            d.eat();
        }
    	public void feed(Cat c){
            c.eat();
        }     
    }
    

    以上的代码中表示:Master与Dog和Cat之间的关系很紧密(耦合度高),从而导致了扩展力差

    public class Master{
    	public void feed(Pet pet){
            pet.eat();
        }
    }
    

    以上表示:Master与Dog以及Cat的关系脱离了(耦合度降低),Master关注的是Pet类,提高了软件的扩展性

    /*
    2.1.多态练习题
    编写程序模拟“主人”喂养“宠物”的场景:
    提示1:
    	主人类:Master
    	宠物类:Pet
    	宠物类子类:Dog、Cat、YingWu
    提示2:
    	主人应该有喂养的方法:feed()
    	宠物应该有吃的方法:eat()
    	只要主人喂宠物,宠物就吃。
    要求:主人类中只提供一个喂养方法feed(),要求达到可以喂养各种类型的宠物。
    编写测试程序:
    	创建主人对象
    	创建各种宠物对象
    	调用主人的喂养方法feed(),喂养不同的宠物,观察执行结果。
    
    通过该案例,理解多态在开发中的作用。
    重要提示:feed方法是否需要一个参数,参数选什么类型!!!
     */
    
    public class Pet {
        public void eat(){}
    }
    
    public class Cat extends Pet{
        public void eat(){
            System.out.println("猫喜欢吃鱼,抓一条给他");
        }
    }
    
    public class Dog extends Pet{
        public void eat(){
            System.out.println("狗狗很喜欢吃肉,给他一块肉,他吃的很香");
        }
    }
    
    public class YingWu extends Pet{
        public void eat(){
            System.out.println("鹦鹉把小虫子都吃掉");
        }
    }
    
    
    //主人类
    public class Master {
    
        /*
        //起初的时候主任只是喜欢养宠物狗
        //喂养宠物狗狗
        public void feed(Dog d){
            d.eat();
        }
    
        //新需求产生,导致我们“不得不”去修改Master这个类
        public void feed(Cat c){
            c.eat();
        }
         */
    
        //怎么做可以使Master类以后不再修改,即使以后又想养其他宠物,Master也不需要再修改。
        //这个时候就需要使用:多态机制。最好不要写具体的宠物类型,这样会影响程序的拓展性
        //public void feed(Cat c){c.eat(); }    如其中传递的参数是cat类型的,就会影响程序的拓展性。
        public void feed(Pet pet){
            //编译时,编译器会去pet类中找eat方法,找到后绑定
            //运行时,底层实际的对象是什么,就自动调用该实际对象对应的eat()方法上
            //这就是多态的使用
            pet.eat();
        }
    
    }
    
    /*
        分析:
            主人起初只想养狗,过了一段时间喜欢上养“猫”
            在实际开发中这个就代表客户产生了新的需求。我们作为开发人员,必须满足客户的需求。
        如何满足需求:
            在不使用多态机制的前提下,目前我们只能在Master中添加一个新的方法
    
        思考:软件在扩展需求过程中,修改Master这个类有什么问题?
            软件在扩展过程中,修改的越少越好。修改的越多,系统当前的稳定性就越差,未知的风险更多
    
            在这里涉及一个软件的开发原则:
                软件开发中有七大原则(属于整个软件行业,不止属于java)
                    其中有一条最基本的原则:OCP(开闭原则)
                什么是开闭原则?
                    拓展开放(可以额外添加),修改关闭(最好不要修改现有程序)
                    在软件拓展过程中,修改的越少越好
    
           程序员开发项目不仅要实现客户的需求,还要考虑软件的拓展性
    
           什么是软件拓展性
               假设电脑上内存部件坏掉了,买一个新的插上就可以直接使用。这个电脑的设计就考虑了“拓展性”。
     */
    
    public class Test {
        public static void main(String[] args){
            //创建主人对象
            Master zhangSan = new Master();
            //创建宠物狗对象
            Dog d = new Dog();
            //喂养宠物狗狗
            zhangSan.feed(d);
            //创建猫对象
            Cat c = new Cat();
            //喂养猫咪
            zhangSan.feed(c);
            //喂养鹦鹉
            zhangSan.feed(new YingWu());
        }
    }
    
    
  3. 面向对象的三大特征:

    ​ 封装、继承、多态。一环扣一环

    有了封装,就有了这种整体的概念。之后,对象和对象之间有了继承。继承之后,才有了方法的覆盖和多态

  4. 软件开发原则

    七大原则中最基本的原则:OCP(对扩展开放,对修改关闭)

    目的:降低耦合度,提高编程能力。面向抽象编程,不建议面向具体编程。

  5. 作业

    /*
        1.编写程序实现乐手弹奏乐器。乐手可以弹奏不同的乐器从而发出不同的声音。
        可以弹奏的乐器包括二胡、钢琴和琵琶。
            实现思路及关键代码:
                1)定义乐器类Instrument,包括方法makeSound()
                2)定义乐器类的子类:二胡Erhu、钢琴Piano和小提琴Violin
                3)定义乐手类Musician,可以弹奏各种乐器play(Instrument i)
                4)定义测试类,给乐手不同的乐器让他弹奏
     */
    public class Homework1 {
        public static void main(String[] args){
            //创建个乐手
            Musician mc = new Musician();
            //让他弹二胡
            mc.play(new ErHu());
            //让他弹钢琴
            mc.play(new Piano());
            //让他拉小提琴
            mc.play(new Violin());
        }
    }
    
    
    public class Instrument {
        public void makeSound(){
    
        }
    }
    
    public class Musician {
        public void play(Instrument i){
            i.makeSound();
        }
    }
    
    
    public class ErHu extends Instrument {
        public void makeSound(){
            System.out.println("二胡音响了");
        }
    }
    
    
    public class Piano extends Instrument{
        public void makeSound(){
            System.out.println("钢琴声响了起来");
        }
    }
    
    
    public class Violin extends Instrument{
        public void makeSound(){
            System.out.println("小提琴拉了起来");
        }
    }
    
    
  6. 解决之前剩下的问题 私有不能覆盖;静态不谈覆盖

    私有方法为什么无法覆盖

    /*
        私有方法不能覆盖
        - java中不能覆盖private修饰的方法,因为private修饰的变量和方法都只能在当前类中使用。
          如果是其他的类继承当前类,是不能访问private修饰的变量/方法的,当然也不能覆盖
        - 覆盖是发生在字类和父类之间的,而private修饰的变量/方法无法被子类继承,子类无法访问,所以更没办法覆盖。
     */
    public class OverrideTest06 {
        public static void main(String[] args){
            //多态
            OverrideTest06 ot = new T0();
            ot.doSome();//父类的私有方法doSome执行
            //也就是说我们重写的公有方法没有执行,就说明私有方法不能覆盖。
        }
        private void doSome(){
            System.out.println("父类的私有方法doSome执行");
        }
    
    }
    /*      在外部类中无法访问私有的。
    class MyMain{
        public static void main(String[] args){
            OverrideTest06 ot = new T0();
            //错误: doSome() 在 OverrideTest06 中是 private 访问控制
            //ot.doSome();
        }
    }
    */
    
    class T0 extends OverrideTest06{
        //尝试重写父类中的doSome 方法,访问权限不能更低,可以更高
        public void doSome(){
            System.out.println("子类的公有方法doSome执行");
        }
    }
    

    方法覆盖为什么只针对“实例方法”,对“静态方法“没有意义

    /*
       1、方法覆盖需要与多态机制联合起来使用才有意义。
           Animal a = new Cat();
           a.move();
           要什么效果?
               编译时move()方法是Animal上的
               运行时自动调用到子类写的move()方法上。
       
           没有多态机制,方法覆盖也可有可无。
       2、静态方法存在方法覆盖吗?
           方法覆盖和多态密不可分,多态自然与对象有关系。而静态方法执行不需要对象
           静态方法使用“类名.”调用,这种不能叫做覆盖。所以我们说静态方法“不存在覆盖”
    */
    
    /*
    - static关键字表示:一个成员变量/方法可以在没有所属类的实例变量情况下访问。
    - java中static方法不能覆盖,因为方法覆盖是基于动态绑定的,而static方法是编译时静态绑定的。
      static方法跟类的任何实例都不相关,所以概念上不适用。
    - static修饰的变量,表示该变量是类变量,属于类而不是属于实例对象,所以可以不通过实例化直接通过类进行访问,也不hi在实例对象内存空间释放后消失
      static修饰的方法,表示该方法是类方法。在类加载后就可以通过类名调用,而不需要创建任何类的实例对象。
    - 子类和父类的方法都必须是实例方法,如果父类是static方法而子类是实例方法(或相反),都会报错。
      如果父类和子类都是static方法,那么子类隐藏父类的方法,而不是重写父类方法
    - 方法覆盖/重写,是发生在子类和父类之间,有继承关系的类之间的,而且是基于动态绑定的,但static修饰的是静态绑定编译的。
     */
    
    public class OverrideTest05 {
        public static void main(String[] args){
            Animal0 a = new Animal0();
            Cat0 c = new Cat0();
            //静态方法可以使用“引用.”来调用吗?
            a.doSome();     //Animal静态
            c.doSome();     //Cat静态
            //虽然使用“引用.”来调用,但是和对象无关。实际运行时还是:
            Animal0.doSome();
            Cat0.doSome();
        }
    }
    
    class Animal0{
        //父类的静态方法
        public static void doSome(){
            System.out.println("Animal静态");
        }
    }
    
    class Cat0 extends Animal0{
        //子类的静态方法
        public static void doSome(){
            System.out.println("Cat静态");
        }
    }

    学习了多态之后,方法覆盖的条件:”返回值类型相同“可以修改一下吗?

    ​ 返回值如果是基本数据类型,想要覆盖,返回值类型必须一致

    ​ 返回值如果是引用数据类型,返回值类型可以变得更小(但意义不大,实际开发中没人这样写)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值