java中的继承 (extends) 详解

java中的继承 (extends) 详解继承(extends)1.父类与子类父类也叫基类、超类子类也叫派生类在继承的而关系中,“子类就是一个父类“。也就是说,子类可以被当做父类来看待。例如父类是员工,子类是老师,那么我们可以说**”老师就是一个员工“**。关系是“is-a”,例如“老师isa员工”2.继承的格式2.1定义父类的格式:(一个普通的类定义)publicclass父类名称…

大家好,又见面了,我是你们的朋友全栈君。

继承(extends)

1. 父类与子类

  • 父类也叫基类、超类

  • 子类也叫派生类

  • 在继承的而关系中,“子类就是一个父类“。也就是说,子类可以被当做父类来看待。例如父类是员工,子类是老师,那么我们可以说**”老师就是一个员工“**。

2. 继承的格式

2.1 定义父类的格式:(一个普通的类定义)

public class 父类名称{ 
   
    //.....
}

2.2 定义子类的格式

public class 子类名称 extends 父类名称{ 
   
    //.....
}

2.3 代码演示(老师类继承员工类)

  • 2.3.1 Employee类
public class Employee(){ 
   
    public void method(){ 
   
        System.out.println("方法执行")
    }
}
  • 2.3.2 Teacher类,继承自Employee类
public class Teacher extends Employee{ 
   
	//我们先不在里面添加任何东西
}

  • 2.3.3 在main中,创建一个Teacher类的对象
public class Main { 
   

    public static void main(String[] args) { 
   
	    Teacher one = new Teacher();
        //Teacher类继承了Empolyee类的方法
	    one.method();
    }
}
/*输出结果: 执行方法 */

2.3.4 小结论

Teacher类继承了Employee类,也就继承了它的 public void method() 方法,达到了代码复用的效果,当父类有我们子类需要用的方法时,我们就不用再去重新打一次,直接可以拿来用。

3. 继承中成员变量的访问特点

3.1 成员变量之间的访问 (变量不重名的情况)

  • 3.1.1 先创立一个父类Fu
public class Fu { 
   
    public int numFu = 10;  //关键字为public,可以直接通过(对象.变量名)访问,方便说明问题
}
  • 3.1.2 再创立一个子类Zi
public class Zi extends Fu{ 
   
    public int numZi = 20;
}
  • 3.1.3 在main中分别建立父类和子类的对象
public class Demo02ExtendsField { 
   
    public static void main(String[] args) { 
   
        //创建父类对象
        Fu fu = new Fu();
        //父类只能找到自己的成员numFu,并没有找到子类的成员numZi
        System.out.println(fu.numFu);

        //创立一个子类对象
        Zi zi = new Zi();
        //子类对象既可以打印父类的成员numFu,也可以打印自己的成员numZi
        //还是那句"先人不知道后人的事情,而后人知道先人的事情"
        System.out.println(zi.numFu);
        System.out.println(zi.numZi);
    }
}

3.2 成员变量之间的访问 (变量重名的情况)

有两种情况:

  1. 直接通过对象访问成员变量:

    等号左边是谁,就优先用谁,没有则向上找

  2. 间接通过成员方法访问成员变量

    该方法属于谁,就优先用谁,没有则向上找

  • 假设现在父类 Fu 和子类 Zi 都有一个变量名叫num

  • Fu 类

    public class Fu { 
         
        public int num = 10;
    
        public void methodFu(){ 
         
            //这里打印的num,一定是本类的,不会再往下找子类的
            System.out.println(num);
        }
    }
    
  • Zi类

    public class Zi extends Fu{ 
         
        public int num = 20;
    
        public void methodZi(){ 
         
            //这里打印的num,如果本类有,就优先打印本类的,如果没有再往上找
            System.out.println(num);
        }
    }
    

第一种情况:直接通过对象访问成员变量

等号左边是谁,就优先用谁,没有则向上找。Fu fu = new Zi();等号的左边是父类

public class Demo02ExtendsField { 
   
    public static void main(String[] args) { 
   
     // Zi zi = new Fu(); 不能通过父类来构造子类,先人(父类)根本不知道后人(子类)长什么样子
        Fu fu = new Zi(); //可以通过子类来构造父类,这时等号左边是父类
        System.out.println(fu.num);  //10,打印的是父类的num
    }
}

第二种情况:间接通过成员方法访问成员变量

public class Demo02ExtendsField { 
   
    public static void main(String[] args) { 
   

        Fu fu = new Fu();
        Zi zi = new Zi();

        //打印的是父类的num,因为该类没有继承其它类,他自己肯定有一个num,才能写出这个方法
        fu.methodFu();  //父类的num 10,补充:没有fu.methodZi(), 先人不知道后人的方法

        //如果子类有一个num,那就优先打印本类的,没有的话再往父类那里找
        zi.methodZi();  //子类的num 20

        //重点!子类用的是父类的方法打印num,这就要看这个方法属于谁,是谁定义的这个方法
        //因为methodFu()这个方法是属于父类的,打印的当然就是父类的num
        zi.methodFu();  //父类的num 10
    }
}

4. 区分子类方法中的重名

假如有好多个num,父类有一个,子类有两个,怎么才能正确地打印想要的那个num呢?

  • 4.1 父类

    public class Fu { 
         
        public int num = 10;
    }
    
  • 4.2 子类

    public class Zi extends Fu { 
         
        public int num = 20;
    
        public void methodZi(){ 
         
            int num = 30;
            System.out.println(num);      //30, 局部变量
            System.out.println(this.num); //20, 本类的成员变量
            System.out.println(super.num);//10, 父类的成员变量
        }
    }
    
  • 4.3 看看子类方法 methodZi() 能不能正确区分三个num

    public class Demo03Main { 
         
        public static void main(String[] args) { 
         
            Zi zi = new Zi();
            zi.methodZi();  //30, 20, 10
        }
    }
    
  • 4.4 总结:要想正确地打印想要的num,可以这样打

    • 局部变量,上面的那个num = 30,就可以直接写
    • 本类的成员变量,上面的num = 20, 用this.成员变量名
    • 父类的成员变量,上面的num = 10, 用super.成员变量名

5. 继承中成员方法重名的问题

假如子类和父类都有一个方法叫 method() , 那怎么知道用的是哪一个呢?

  • 5.1 父类

    public class Fu { 
         
        public void method(){ 
         
            System.out.println("父类重名方法执行");
        }
    }
    
  • 5.2 子类

    public class Zi extends Fu { 
         
        public void method(){ 
         
            System.out.println("子类重名方法执行");
        }
    }
    
  • 5.3 在main中调用 method() 方法

    public class Demo04Main { 
         
        public static void main(String[] args) { 
         
            Fu fu1 = new Fu();
            Fu fu2 = new Zi(); //通过子类来构造fu2
            Zi zi = new Zi();
    
            fu1.method(); //父类重名方法执行, 用的是父类方法
            fu2.method(); //子类重名方法执行,用的是子类方法
            zi.method();  //子类重名方法执行, 用的是子类方法
        }
    }
    
  • 结论 :

  1. 创建的对象是谁,用谁的类来构造对象的,就优先用谁,如果没有就向上找。比如Fu fu2 = new Zi();,fu2是用子类来构造的,那fu2.method()就是用的子类的方法
  2. 注意!无论是成员变量还是成员方法,如果没有都是向上找父类,绝对不会向下找子类的。

6. 继承方法中的覆盖重写

5. 继承中成员方法重名的问题,我们可以引出重写(Override)的概念

重写:在继承关系中,方法的名称一样,参数列表也一样

  • 6.1 重写 (Override) 和 重载 (Overload) 的区别

    重写:方法的名称一样,参数列表【也一样】。也叫覆盖、覆写

    重载:方法的名称一样,参数列表【不一样】。

  • 6.2 覆盖重写的注意事项 (了解)

    • 6.2.1 必须保证父子类之间方法的名称相同,参数列表也相同,否则无法进行覆盖重写

    • 6.2.2 注解:@Override,这个注解写在方法的前面,用来检验是不是有效的覆盖重写,例如当方法名写错了,@Override底下就会出现红色的波浪线,提示你这不是有效的覆盖重写。

      public class Zi extends Fu { 
             
          @Override
          public void method(){ 
             
              System.out.println("子类重名方法执行");
          }
      }
      

      这个注解可写可不写,但是强烈推荐把它写上去。

    • 6.2.3 子类方法的返回值必须【小于等于】父类方法的返回值范围。java.lang.Object是所有类的公共最高父类(祖宗类),每个类都默认继承了它,例如String类就是Object的子类。下面代码会报错,是因为返回值的范围问题

      • 6.2.3.1 父类

        public class Fu { 
                 
            public String method(){ 
                 
                System.out.println("父类重名方法执行");
            }
        }
        
      • 6.2.3.2 子类

        public class Zi extends Fu { 
                 
            @Override
            public Object method(){ 
                   //范围:Object > String 报错
                System.out.println("子类重名方法执行");
            }
        }
        
    • 6.2.4 子类方法的权限必须【大于等于】父类方法的权限修饰符。权限的排名:public > protected > (default) > private。备注:(default)不是关键字default,而是什么都不写,留空,例如:

      public class Fu{ 
             
          int num; //num的访问权限是default
      }
      

      下面的代码会因为重写方法的权限问题而报错:

      • 6.2.4.1 父类

        public class Fu { 
                 
            public void method(){ 
                 
                System.out.println("父类重名方法执行");
            }
        }
        
      • 6.2.4.2 子类

        public class Zi extends Fu { 
                 
            @Override
            protected void method(){ 
                   //protected < public 报错
                System.out.println("子类重名方法执行");
            }
        }
        
        
  • 6.3 覆盖重写实战演练

    假如旧手机的功能有打电话、发短信、来电显示(显示号码)

    新手机的功能有来电显示、发短信、来电显示(显示号码、显示头像、显示姓名)

    可见新旧手机的打电话和发短信功能是一样的,但是新手机的来电显示功能比旧手机多了显示头像、显示姓名。

    我们可以把旧手机当做父类,把新手机当做子类,新手机只需要重写旧手机的来电显示功能即可

    • 6.3.1 旧手机是父类,名为Oldphone类

      public class Oldphone { 
               
          //打电话功能
          public void call(){ 
             
              System.out.println("打电话");
          }
          //发短信功能
          public void send(){ 
             
              System.out.println("发短信");
          }
          //来电显示功能
          public void show(){ 
             
              System.out.println("显示号码");
          }
      }
      
    • 6.3.2 新手机是子类,名为Newphone类

      public class Newphone extends Oldphone{ 
             
      
          @Override
          public void show() { 
             
              super.show();  //不要修改原来的代码,直接通过super调用它,后面再添加新的内容
              System.out.println("显示头像");
              System.out.println("显示姓名");
          }
      }
      
    • 6.3.3 在main中实验一下

      public class Demo05Main { 
             
          public static void main(String[] args) { 
             
              Newphone newphone = new Newphone();
              newphone.call();
              newphone.send();
              newphone.show();
          }
      }
      /*输出结果: 打电话 发短信 显示号码 显示头像 显示姓名 */
      

7. 继承中构造方法的访问特点

7.1 概述

子类的构造方法启动时,一定会先跑去启动父类的构造方法,等父类的构造方法执行完后,再去执行子类(本类)的构造方法。

7.2 代码说明一下7.1

  • 7.2.1 父类(只有无参构造方法)

    public class Fu { 
         
        //父类的无参构造方法
        public Fu(){ 
         
            System.out.println("父类构造方法执行");
        }
    }
    
    
  • 7.2.2 子类

    public class Zi extends Fu { 
         
        //子类的无参构造方法
        public Zi(){ 
         
            System.out.println("子类构造方法执行");
        }
    }
    
    
  • 7.2.3 在main中构造一个子类

    public class Demo06Main { 
         
        public static void main(String[] args) { 
         
            Zi zi = new Zi();
        }
    }
    
    /*输出结果: 父类构造方法执行 子类构造方法执行 */
    
  • 7.2.4 小总结

    其实子类的构造方法中隐含了super()调用,如果子类的构造方法没有写super(),编译器会帮我们默认加上去。子类就变成

    public class Zi extends Fu { 
         
        //子类的无参构造方法
        public Zi(){ 
         
            super();  //注意!这句必须写在第一行的位置,如果父类构造函数有参数,就是super(参数),有 参数的调用,必须要自己写上去,不然会默认调用无参构造
            System.out.println("子类构造方法执行");
        }
    }
    

8. super关键字的三种用法总结

8.1 用法1

在子类的成员方法中,访问父类的成员变量,比如:

  • 8.1.1 父类

    public class Fu { 
         
        public int num = 10;
    }
    
  • 8.1.2 子类

    public class Zi extends Fu { 
         
        public int num = 20;
    
        public void methodZi(){ 
         
           // System.out.println(num); 这样打印的一定是本类的num
            System.out.println(super.num); //打印的是父类的num
        }
    }
    

8.2 用法2

在子类的成员方法中,访问父类的成员方法,比如:

  • 8.2.1 父类

    public class Fu { 
         
        public void methodFu(){ 
         
            System.out.println("父类的成员方法执行");
        }
    }
    
    
  • 8.2.2 子类

    public class Zi extends Fu{ 
         
        public void methodZi(){ 
         
            super.methodFu(); //访问父类的methodFu()方法
            System.out.println("子类的成员方法执行");
        }
    }
    
  • 在main中执行子类的方法

    public class Demo07Main { 
         
        public static void main(String[] args) { 
         
            Zi zi = new Zi();
            zi.methodZi();
        }
    }
    /*输出结果: 父类的成员方法执行 子类的成员方法执行 */
    

8.3 用法3

在子类的构造方法中,访问父类的构造方法。就在 7. 继承中构造方法的访问特点 中,请自行查阅。

9. this关键字的三种用法

9.1 概述

9.1.1 在本类的成员方法中,访问本类的成员变量

9.1.2 在本类的成员方法中,访问本类的另一个成员方法

9.1.3 在本类的构造方法中,访问本类的另一个构造方法

9.2 代码说明一下

public class Zi extends Fu { 
   
    private int num = 10;

    public Zi(){ 
   
        this(123);  //9.1.3 在本类的无参构造中调用有参构造
    }

    public Zi(int num){ 
   
        this.num = num;
    }

    public void methodZi(){ 
   
        System.out.println(this.num); //9.1.1 在本类的成员方法中,访问本类的成员变量
    }

    public void methodA(){ 
   
        System.out.println("A方法");
    }

    public void methodB(){ 
   
        this.methodA();  //9.1.2 在本类的成员方法中,访问本类的另一个成员方法
        System.out.println("B方法"); 

9.3 注意事项

  • 在构造方法中调用this,那这个this调用必须是该函数中的第一个语句,也是唯一的一个
  • super和this两种在构造调用中,不能同时使用。两个都要排在第一行,我哪知道该怎么排。

10. java继承的三个特点

10.1 java语言是单继承

一个类的直接父类只能有唯一的一个。

class A{ 
   }
class B extends A{ 
   }  正确写法
class C{ 
   }
class D extends A,C{ 
   } 错误写法,不能同时继承A和C

试想假如class A{}有一个 method() 方法,

Class C{}也有一个 method() 方法,

子类D同时继承类A和类C,那当我新建一个D类对象d后,

对象d想要调用父类的method方法,那它应该用A的 method() 还是C的 method() 呢?这就乱套了!

在这里插入图片描述

10.2 java语言是可以多级继承的

虽然,java语言是单继承的,一个类的直接父类只有一个,类D不能同时继承类A和类C

但是,可以让类A继承类C之后,类D再继承类A,C就是爷爷,A就是爸爸,D就是儿子

类D –> 类A –> 类C,这就叫多级继承。
在这里插入图片描述

10.3 java语言中,一个父类可以有多个子类

这就好比二胎政策,一个爸爸可以有多个儿子

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/160112.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 计算机网络之TCP/UDP协议详解[通俗易懂]

    计算机网络之TCP/UDP协议详解[通俗易懂]深度理解TCP/IP1.TCP基础知识1.1什么是TCP?1.2什么是TCP连接?1.3TCP协议段格式1.4TCP主要特点2.UDP基础知识2.1UDP是什么?2.2UDP的协议段格式2.3UDP的主要特点2.4UDP的缓冲区3.TCP和UDP区别总结4.TCP保证可靠的机制4.1重传机制(这里只说了超时重传)4.2滑动窗口4.3流量控制4.3拥塞控制1.TCP基础知识1.1什么是TCP?TCP是⾯向连接的、可靠的、面向字节流的传输层通信协议面向连接:只能一对一连接,

    2022年5月9日
    36
  • RealSense RGBD 深度摄像头 D435i 、D455 硬件结构及各个组件原理详解「建议收藏」

    RealSense RGBD 深度摄像头 D435i 、D455 硬件结构及各个组件原理详解「建议收藏」文章目录D435i硬件结构图D435i介绍视角知识补充标准镜头广角镜头长焦镜头广角镜头和长焦镜头的区别主要在于焦距不同、取景范围不同和拍摄对象不同。鱼眼镜头和广角镜头的区别IRLaserProjector介绍测距方式汇总3D结构光介绍RGB-D相机的TOF工作原理实际应用案例librealsenserealsense-rosD455D435i官方链接:https://www.intelrealsense.com/zh-hans/depth-camera-d435i/先来看一下实际图片硬件结构

    2022年9月18日
    2
  • JAVA设计模式初探之装饰者模式

    这个模式花费了挺长时间,开始有点难理解,其实就是定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。设计初衷:通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。…

    2022年3月11日
    37
  • cisco logging 配置

    cisco logging 配置

    2021年8月20日
    49
  • 朋友圈集赞万能截图生成器微信小程序源码下载

    朋友圈集赞万能截图生成器微信小程序源码下载大家好这是一款朋友圈积攒截图小程序里面内涵三款样式生成,一款图文,一款分享,一款查看的样式也就是我们微信朋友圈所用到的样式就包含了里面的流量主那些可以用户自由的添加哈!赞的数量那些可以用户自定义的哈另外所需的内容也是用户自定义的安装方法的话和往常一样!直接微信开发者工具打开源码然后设置一个合法域名上传审核就可以了合法域名在压缩包里面,搭建解压了就可以看到了小程序源码下载地址:(442条消息)朋友圈集赞万能截图生成器微信小程序源码下载-小程序文档类资源-CSDN文库ht

    2025年9月20日
    6
  • SM4算法原理_sgp4算法

    SM4算法原理_sgp4算法前面的文章介绍了SM4算法的C语言实现,源码可见我的另一篇文章:https://blog.csdn.net/cg129054036/article/details/83012721;这篇文章介绍SM4算法原理,这部分可能会比较枯燥,但数学要求也不是太高。目录1.概述2.参数产生3.轮函数4.密钥扩展5.加密/解密过程1.概述2012年3月,国家密码管理…

    2022年10月5日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号