深刻理解java继承从“我爸是李刚”讲起

前言
本文主要多方面讲解java继承,旨在让初学者通俗易懂,至于“我爸是李刚”,反正楼主也不知道谁爸是李刚。
@java

一、继承的概述

1.一、继承的由来

至于由来简单一句话:多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为。ide

继承描述的是事物之间的所属关系,这种关系是 is-a 的关系。函数

1.二、继承的定义

继承:就是子类继承父类的属性行为,使得子类对象具备与父类相同的属性、相同的行为。子类能够直接访问父类中的非私有的属性和行为。this

这里再声明一点,父类又称为超类或者基类。而子类又称为派生类这点很基础!编码

1.三、继承的优势

  1. 提升代码的复用性
  2. 类与类之间产生关系,为多态作了完美的铺垫(不理解不要紧,以后我会再写一篇多态的文章)

虽然继承的优势不少可是Java只支持单继承,不支持多继承.net

1.四、继承的格式

经过 extends 关键字,能够声明一个子类继承另一个父类,定义格式以下:code

class 父类 {
   ... 
   }
   class 子类 extends 父类 { 
   ... 
   }

二、关于继承以后的成员变量

当类之间产生了关系后,其中各种中的成员变量,产生了哪些影响呢? 关于继承以后的成员变量要从两方面下手,一是成员变量不重名方面,二是成员变量重名方面。对象

2.一、成员变量不重名

若是子类父类中出现不重名的成员变量,这时的访问是没有影响的。代码以下:blog

class liGang {
        // 父类中的成员变量。
       String name ="李刚";//------------------------------父类成员变量是name
    }
    class LiXiaoGang extends liGang {
        // 子类中的成员变量
        String name2 ="李小刚";//--------------------------子类成员变量是name2
        // 子类中的成员方法
        public void show() {
            // 访问父类中的name,
            System.out.println("我爸是"+name);
            // 继承而来,因此直接访问。
            // 访问子类中的name2
            System.out.println("我是"+name2);
        }
    }
public class Demo {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang z = new LiXiaoGang();
            // 调用子类中的show方法
            z.show();
        }
    }
    //演示结果: 我爸是李刚   我是李小刚

2.二、 成员变量重名

若是子类父类中出现重名的成员变量,这时的访问是有影响的。代码以下:

class liGang {
        // 父类中的成员变量。
       String name ="李刚";//------------------------------父类成员变量是name
    }
    class LiXiaoGang extends liGang {
        // 子类中的成员变量
        String name ="李小刚";//---------------------------子类成员变量也是name
        // 子类中的成员方法
        public void show() {
            // 访问父类中的name,
            System.out.println("我爸是"+name);
            // 继承而来,因此直接访问。
            // 访问子类中的name2
            System.out.println("我是"+name);
        }
    }
public class Demo {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang z = new LiXiaoGang();
            // 调用子类中的show方法
            z.show();
        }
    }
    //演示结果: 我爸是李小刚   我是李小刚

子父类中出现了同名的成员变量时,在子类中须要访问父类中非私有成员变量时,须要使用 super 关键字,至于修饰父类成员变量,相似于以前学过的 this 。 使用格式 super.父类成员变量名

this表示当前对象,super则表示父类对象,用法相似!

class liGang {
        // 父类中的成员变量。
       String name ="李刚";
    }
    class LiXiaoGang extends liGang {
        // 子类中的成员变量
        String name ="李小刚";
        // 子类中的成员方法
        public void show() {
            // 访问父类中的name,
            System.out.println("我爸是"+super.name);
            // 继承而来,因此直接访问。
            // 访问子类中的name2
            System.out.println("我是"+this.name);  //固然this可省略
        }
    }
public class Demo {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang z = new LiXiaoGang();
            // 调用子类中的show方法
            z.show();
        }
    }
    //演示结果: 我爸是李刚   我是李小刚

2.三、关于继承中成员变量值得思考的一个问题

同窗你有没有想过这样一个问题。若是父类中的成员变量
非私有:子类中能够直接访问。
私有:子类是不能直接访问的。以下:
在这里插入图片描述
固然,同窗你要本身体验体验编译报错过程,看图没体验感不得劲,~呕,你这无处安放的魅力,无理的要求,我佛了,行吧~

class liGang2 {
        // 父类中的成员变量。
        private String name ="李刚";

    }
    class LiXiaoGang2 extends liGang2 {
        // 子类中的成员变量
        String name ="李小刚";
        // 子类中的成员方法
        public void show() {
            // 访问父类中的name,
            System.out.println("我爸是"+super.name);//------编译失败不能直接访问父类私有属性(成员变量)
            // 继承而来,因此直接访问。
            // 访问子类中的name2
            System.out.println("我是"+this.name);  //固然this可省略
        }
    }
public class PrivateVariable {
        public static void main(String[] args) {
            // 建立子类对象
            ExtendDemo.LiXiaoGang z = new ExtendDemo.LiXiaoGang();
            // 调用子类中的show方法
            z.show();
        }
    }

一般开发中编码时,咱们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员变量呢?其实这个时候在父类中提供公共的getXxx方法和setXxx方法就能够了。代码以下:

class liGang {
        // 父类中的成员变量。
      private String name ="李刚";

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    class LiXiaoGang extends liGang {
        // 子类中的成员变量
        String name ="李小刚";
        // 子类中的成员方法
        public void show() {
            // 访问父类中的name,
            System.out.println("我爸是"+super.getName());
            // 继承而来,因此直接访问。
            // 访问子类中的name2
            System.out.println("我是"+this.name);  //固然this可省略
        }
    }
public class Demo {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang z = new LiXiaoGang();
            // 调用子类中的show方法
            z.show();
        }
    }
    //演示结果: 我爸是李刚   我是李小刚

分析以下:在这里插入图片描述

三、关于继承以后的成员方法

分析完了成员变量,如今咱们一块儿来分析分析成员方法。
想想,当类之间产生了关系,其中各种中的成员方法,又产生了哪些影响呢? 一样咱们依旧从两方面分析。
#### 3.一、成员方法不重名
若是子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对 应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。代码以下:

class liGang3 {
        // 父类中的成员方法。
       public void zhuangRen1(){//--------------------------父类方法名zhuangRen1
           System.out.println("我叫李刚,人不是我撞的,别抓我,我不认识李小刚");
       }
    }
    class LiXiaoGang3 extends liGang3 {

        // 子类中的成员方法
        public void zhuangRen() {//--------------------------子类方法名zhuangRen
            System.out.println("有本事大家告去,我爸是李刚");  
        }
    }
    public class MemberMethod {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang3 liXiaoGang = new LiXiaoGang3();
            // 调用子类中的show方法
            liXiaoGang.zhuangRen();
            liXiaoGang.zhuangRen1();
        }
    }
    
打印结果:有本事大家告去,我爸是李刚
        我叫李刚,人不是我撞的,别抓我,我不认识李小刚

在这里插入图片描述
#### 3.二、成员方法重名 【方法重写】
成员方法重名大致也能够分两种状况:

一、方法名相同返回值类型、参数列表却不相同(优先在子类查找,没找到就去父类)
二、方法名、返回值类型、参数列表都相同,没错这就是重写(Override)

这里主要讲方法重写 :子类中出现与父类如出一辙的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,从新实现。 代码以下:

class liGang3 {
        // 父类中的成员方法。
       public void zhuangRen(int a){
           System.out.println("我叫李刚,人不是我撞的,别抓我");
       }
    }
    class LiXiaoGang3 extends liGang3 {

        // 子类中的成员方法
        public void zhuangRen(int a) {
            System.out.println("有本事大家告去,我爸是李刚");
        }
    }
    public class MemberMethod {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang3 liXiaoGang = new LiXiaoGang3();
            // 调用子类中的zhuangRen方法
            liXiaoGang.zhuangRen(1);

        }
    }
    结果打印:有本事大家告去,我爸是李刚

#### 3.三、继承中重写方法的意义
子类能够根据须要,定义特定于本身的行为。既沿袭了父类的功能名称,又根据子类的须要从新实现父类方法,从而进行扩展加强。好比李刚会开车,李小刚就牛了,在父类中进行扩展加强还会开车撞人,代码以下:

class liGang3 {
        // 父类中的成员方法。
       public void kaiChe(){
           System.out.println("我会开车");
       }
    }
    class LiXiaoGang3 extends liGang3 {
        // 子类中的成员方法
        public void kaiChe(){
            super.kaiChe();
            System.out.println("我还会撞人");
            System.out.println("我还能一撞撞俩婆娘");
        }
    }
    public class MemberMethod {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang3 liXiaoGang = new LiXiaoGang3();
            // 调用子类中的zhuangRen方法
            liXiaoGang.kaiChe();

打印结果:   我会开车
           我还会撞人
           我还能一撞撞俩婆娘
        }
    }

不知道同窗们发现了没有,以上代码中在子类中使用了 super.kaiChe();super.父类成员方法,表示调用父类的成员方法。

最后重写必须注意这几点:

一、方法重写时, 方法名与形参列表必须一致。
二、子类方法覆盖父类方法时,必需要保证子类权限 >= 父类权限。
三、方法重写时,子类的返回值类型必需要 <= 父类的返回值类型。
四、方法重写时,子类抛出的异常类型要 <= 父类抛出的异常类型。

粗心的同窗看黑板,look 这里【注意:只有访问权限是>=,返回值、异常类型都是<=

下面以修饰权限为例,以下:

在这里插入图片描述

四、关于继承以后的构造方法

为了让你更好的体会,首先我先编写一个程序

class liGang4 {
        // 父类的无参构造方法。
        public liGang4(){
            System.out.println("父类构造方法执行了。。。");
        }
    }
    class LiXiaoGang4 extends liGang4 {
        // 子类的无参构造方法。
       public LiXiaoGang4(){
           System.out.println("子类构造方法执行了====");
       }
    }
    public class ConstructionDemo {
        public static void main(String[] args) {
            // 建立子类对象
            LiXiaoGang4 z = new LiXiaoGang4();

        }
    }

用一分钟猜测一下结果是什么,猜好了再看下面结果:

父类构造方法执行了。。。
子类构造方法执行了====

好了,看告终果以后,你可能有疑惑。父类构造器方法怎么执行了?咱们先来分析分析,首先在main方法中实例化了子类对象,接着会去执行子类的默认构造器初始化,这个时候在构造方法中默认会在第一句代码中添加super();没错,他就是开挂般的存在,不写也存在的!有的调~读四声“跳”~皮的同窗就会说,你说存在就存在啊,无凭无据 ~呀,你这个该死的靓仔~ 以下:
在这里插入图片描述
构造方法的名字是与类名一致的,因此子类是没法继承父类构造方法的。 构造方法的做用是初始化成员变量的。因此子类的初始化过程当中,必须先执行父类的初始化动做。子类的构造方法中默认会在第一句代码中添加super(),表示调用父类的构造方法,父类成员变量初始化后,才能够给子类使用。

固然我已经强调不少遍了 super() 不写也默认存在,并且只能是在第一句代码中,不在第一句代码中行不行,答案是固然不行,这样会编译失败,以下:
在这里插入图片描述

五、关于继承的多态性支持的例子

直接上代码了喔

class A{
    public String show(C obj) {
        return ("A and C");
    }

    public String show(A obj) {
        return ("A and A");
    }

}
class B extends A{
    public String show(B obj) {
        return ("B and B");
    }
}
class C extends B{
    public String show(A obj) {
        return ("A and B");
    }
}
public class Demo1 {
    public static void main(String[] args) {
        A a=new A();
        B b=new B();
        C c=new C();
        System.out.println("第一题 " + a.show(a));
        System.out.println("第二题 " + a.show(b));
        System.out.println("第三题 " + a.show(c));
    }
}
运行结果:
        第一题 A and A
        第二题 A and A
        第三题 A and C

其实吧,第一题和第三题都好理解,第二题就有点意思了,会发现A类中没有B类型这个参数,这个时候,你就应该知道子类继承就是父类,换句话说就是子类自然就是父类,好比中国人确定是人,可是人不必定是中国人(多是火星人也多是非洲人),因此父类作为参数类型,直接传子类的参数进去是能够的,反过来,子类作为参数类型,传父类的参数进去,就须要强制类型转换。

六、super与this的用法

了解他们的用法以前必须明确一点的是父类空间优先于子类对象产生

在每次建立子类对象时,先初始化父类空间,再建立其子类对象自己。目的在于子类对象中包含了其对应的父类空间,即可以包含其父类的成员,若是父类成员非private修饰,则子类能够随意使用父类成员。代码体如今子类的构 造方法调用时,必定先调用父类的构造方法。理解图解以下:
在这里插入图片描述
#### 5.一、 super和this的含义:

super :表明父类的存储空间标识(能够理解为父亲的引用)。

 

this :表明当前对象的引用(谁调用就表明谁)。

#### 5.二、 super和this访问成员

this.成员变量 ‐‐ 本类的
super.成员变量 ‐‐ 父类的
this.成员方法名() ‐‐ 本类的
super.成员方法名() ‐‐ 父类的

#### 5.三、super和this访问构造方法

this(...) ‐‐ 本类的构造方法
super(...) ‐‐ 父类的构造方法

#### 5.四、super()和this()能不能同时使用?

不能同时使用,thissuper不能同时出如今一个构造函数里面,由于this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,因此在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会经过。
#### 5.五、总结一下super与this

子类的每一个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()super()this() 都必须是在构造方法的第一行,因此不能同时出现

到这里,java继承你get到了咩,get到了请咩一声,随便随手~点个赞呗~

推荐阅读本专栏的下一篇java文章

【java基础之多态】理解多态的向上向下转型从“妈妈我想吃烤山药”讲起

欢迎各位关注个人公众号,一块儿探讨技术,向往技术,追求技术...

在这里插入图片描述

相关文章
相关标签/搜索