JAVA基础再回首(六)——父与子的继承、super关键字、方法重写、方法重载

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52098499

JAVA基础再回首(六)——父与子的继承、super关键字、方法重写、方法重载

不墨迹,才是时间管理的最大利器,学无止境。

继承

首先我们来学习继承的概述

  • 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
  • 通过extends关键字可以实现类与类的继承
    • 格式:class 子类名 extends 父类名 {}
  • 单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
  • 有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。

以前我们没有学习继承之前,是这样定义一个类和类中的方法的。

//使用继承前
class Student {
    public void eat() {
        System.out.println("吃饭");
    }
    public void sleep() {
        System.out.println("睡觉");
    }
}

class Teacher {
    public void eat() {
        System.out.println("吃饭");
    }
    public void sleep() {
        System.out.println("睡觉");
    }
}

通过观察我们可以学生类和老师类他们都有共同的方法就是吃和睡,既然老司机已经带我们上路了,那么我们就可以改进上面的代码,将相同的成员抽取到一个类中,争取早日成为一名老司机。

//使用继承后
//首先我们定义一个人类,因为老师、学生都属于人,都要吃饭和睡觉
class Person {
    public void eat() {
        System.out.println("吃饭");
    }
    public void sleep() {
        System.out.println("睡觉");
    }
}
class Student extends Person {}

class Teacher extends Person {}

public class ExtendsDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.eat();
        s.sleep();
        System.out.println("-------------");
        Teacher t = new Teacher();
        t.eat();
        t.sleep();
    }
}

作为小司机可以看到使用继承前后的输出结果相同
运用了继承后,我们可以看到继承的好处也就是优点

  • 提高了代码的复用性
    • 多个类相同的成员可以放到同一个类中
  • 提高了代码的维护性
    • 如果功能的代码需要修改,修改一处即可
  • 让类与类之间产生了关系,是多态的前提

当然运用了继承后,他也是存在弊端的

  • 类的耦合性很强
    设计原则:高内聚低耦合。
    简单的理解:
    内聚就是自己完成某件事情的能力。
    耦合就是类与类之间的关系。
    我们在设计的时候原则是:自己能完成的就不麻烦别人,这样将来别人产生了修改,就对我的影响较小。
    由此可见:在开发中使用继承其实是在使用一把双刃剑。今天我们还是以继承的好处来使用,因为继承还有很多其他的特性。

我们了解了继承的概述,继续了解Java中继承的特点

  • Java只支持单继承,不支持多继承。
    • 一个类只能有一个父类,不可以有多个父类。
    • class SubDemo extends Demo{} //ok
    • class SubDemo extends Demo1,Demo2…//error
  • Java支持多层继承(继承体系)
    • class A{}
    • class B extends A{}
    • class C extends B{}

我们一起写个小Demo验证继承的特点!

//Java只支持单继承,不支持多继承。
class Father {}
class Mother {}
class Son exnteds Father {} //正确的
class Son extends Father,Mother {} // 错误的

//Java支持多层继承
class GrandFather {
    public void show() {
        System.out.println("我是爷爷");
    }
}
class Father extends GrandFather {
    public void method(){
        System.out.println("我是老子");
    }
}
class Son extends Father {}
class ExtendsDemo2 {
    public static void main(String[] args) {
        Son s = new Son();
        s.method(); //使用父亲的
        s.show(); //使用爷爷的
    }
}

那么,在Java中继承的注意事项有哪些呢?

  • 子类只能继承父类所有非私有的成员(成员方法和成员变量)
    • 其实这也体现了继承的另一个弊端:打破了封装性
  • 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
  • 不要为了部分功能而去继承
  • 我们到底在什么时候使用继承呢?
    • 继承中类之间体现的是:”is a”的关系。
    • 举例:水果和苹果,苹果是一种水果。
    • 学生和人,学生是人的一种。
    • 所以我们总结采用假设法。如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
class Father {
        private int num = 10;
        public int num2 = 20;

        //私有方法,子类不能继承
        private void method() {
            System.out.println(num);
            System.out.println(num2);
        }

        public void show() {
            System.out.println(num);
            System.out.println(num2);
        }
    }
    class Son extends Father {
        public void function() {
            //num可以在Father中访问private
            //System.out.println(num); //子类不能继承父类的私有成员变量
            System.out.println(num2);
        }
    }
public class ExtendsDemo {

    public static void main(String[] args) {
        // 创建对象
                Son s = new Son();
                //s.method(); //子类不能继承父类的私有成员方法
                s.show();
                s.function();
    }
}

输出结果:
10
20
20

继承中成员变量的关系

  • A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。
  • B:子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢?
    • 结论在子类方法中访问一个变量的查找顺序:
      • a:在子类方法的局部范围找,有就使用
      • b:在子类的成员范围找,有就使用
      • c:在父类的成员范围找,有就使用
      • d:如果还找不到,就报错。
class Father {
    public int num = 10;

    public void method() {
        int num = 50;
    }
}

class Son extends Father {
    public int num2 = 20;
    public int num = 30;

    public void show() {
        int num = 40;
        System.out.println(num);
        System.out.println(num2);
        // 找不到符号,报错
        //System.out.println(num3);
    }
}
public class ExtendsDemo {

    public static void main(String[] args) {
                // 创建对象
                Son s = new Son();
                s.show();   
    }
}

输出结果:
这里写图片描述
记住上面的结论,到哪里都不会出错的
下面来学习super关键字

super关键字

  • super的用法和this很像
    • this代表本类对应的引用。
    • super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)
  • 用法(this和super均可如下使用)
    • 访问成员变量
      • this.成员变量 调用本类的成员变量
      • super.成员变量 调用父类的成员变量
  • 访问构造方法
    • this(…) 调用本类的构造方法
    • super(…) 调用父类的构造方法
  • 访问成员方法
    • this.成员方法() 调用本类的成员方法
    • super.成员方法() 调用父类的成员方法
class Father {
    public int num = 10;
}

class Son extends Father {
    public int num = 20;

    public void show() {
        int num = 30;
        System.out.println(num);
        System.out.println(this.num);
        System.out.println(super.num);
    }
}

public class ExtendsDemo{
    public static void main(String[] args) {
        Son s = new Son();
        s.show();
    }
}

输出结果:
这里写图片描述

继承中构造方法的关系

  • 子类中所有的构造方法默认都会访问父类中空参数的构造方法
    • 因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
    • 注意:子类每一个构造方法的第一条语句默认都是:super();
class Father {
    int age;

    public Father() {
        System.out.println("Father的无参构造方法");
    }

    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}
class Son extends Father {
    public Son() {
        //super();
        System.out.println("Son的无参构造方法");
    }

    public Son(String name) {
        //super();
        System.out.println("Son的带参构造方法");
    }
}   

public class ExtendsDemo {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("宝宝");
    }
}

输出结果:
这里写图片描述

如果父类没有无参构造方法,那么子类的构造方法会出现什么现象呢?我注释了上面例子中父类的无参构造,然后项目报错了,那么我们怎么解决呢?

  1. 在父类中加一个无参构造方法
  2. 通过使用super关键字去显示的调用父类的带参构造方法
  3. 子类通过this去调用本类的其他构造方法
  4. (子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。)
  5. 注意事项
  6. this(…)或者super(…)必须出现在第一条语句上。
  7. 如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。

上面说了这么多,不知道你是否理解了,我们通过Demo再来学习

class Father {
    int age;

    /*public Father() {
        System.out.println("Father的无参构造方法");
    }*/

    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}
class Son extends Father {
    public Son() {
        super("111");
        System.out.println("Son的无参构造方法");
//      super("111");
    }

    public Son(String name) {
//      super("222");
        this();
        System.out.println("Son的带参构造方法");
    }
}
public class ExtendsDemo {

    public static void main(String[] args) {
                //创建对象
                Son s = new Son();
                System.out.println("------------");
                Son s2 = new Son("宝宝");
    }
}

输出结果:不知道你通过上面的概念是否能观察出结果呢,不能的话就要去多想多练多理解
这里写图片描述

继承中成员方法的关系:

  • A:子类中的方法和父类中的方法声明不一样,这个太简单。
  • B:子类中的方法和父类中的方法声明一样,这个该怎么玩呢?
    • 通过子类对象调用方法:
      • a:先找子类中,看有没有这个方法,有就使用,没有就在父类中找
      • b:再看父类中,有没有这个方法,有就使用
      • c:如果没有就报错。

方法重写、方法重载

  • 方法重写概述
    • 子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写。
  • 方法重载概述
    • 本类中出现的方法名一样,参数列表不同的方法。与返回值无关。
  • 使用特点:
    • 如果方法名不同,就调用对应的方法
    • 如果方法名相同,最终使用的是子类自己的
  • 方法重写的应用:
    • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
class Phone {
    public void call(String name) {
        System.out.println("给"+name+"打电话");
    }
}
class NewPhone extends Phone {
    public void call(String name) {
        super.call(name);
        System.out.println("打完电话了,我要听首歌");
    }
}
public class ExtendsDemo {

    public static void main(String[] args) {
        NewPhone np = new NewPhone();
        np.call("老板");
    }
}

输出结果:
这里写图片描述
上面的Demo中,手机打电话功能,是手机本身就具备的最基本的功能。所以,新手机是不用在提供这个功能的。由于它继承了手机类,所以,我们就直接使用父类的功能即可。通过super关键字调用

  • 方法重写的注意事项
    • A:父类中私有方法不能被重写(因为父类私有方法子类根本就无法继承)
    • B:子类重写父类方法时(访问权限不能更低,最好就一致)
    • C:父类静态方法,子类也必须通过静态方法进行重写
    • 子类重写父类方法的时候,最好声明一模一样。

我们一起来做两个经典例题

  • 方法重写(Override)和方法重载(Overload)的区别?方法重载能改变返回值类型吗?

    方法重写:在子类中,出现和父类中一模一样的方法声明的现象。
    方法重载:同一个类中,出现的方法名相同,参数列表不同的现象。

    方法重载能改变返回值类型,因为它和返回值类型无关。

  • this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。

    this:代表当前类的对象引用
    super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)
    场景:
    成员变量:this.成员变量——super.成员变量
    构造方法:this(…)——super(…)
    成员方法:this.成员方法——super.成员方法


好了,今天我们学了这么多,要好好消化一下,做到学以致用。最后送大家一句话。
不管有多苦,千万要记住:苦难是我们人生路上不可缺少的经历,只有活着,才有幸福的可能!

阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页