继承和final关键字

2024-01-03 19:53:08

前言:?

? ? ? ?这一篇,我们就来学习面向对象的第二大特征-继承(一定要有类的基础,详情请看Java中的类和方法(方法重载)-CSDN博客)。

什么是继承?

? ? ? ?当我们创建两个类时,发现这两个类都有公共特征时,就可以利用继承,减少相同的代码量。

? ? ? ?我们定义两个类,一个狗类一个猫类,他们都有相同的几个属性:姓名、年龄。一个相同的方法:吃饭。

class Dog{
    public String name;
    public int age;

    public void eat(){
        System.out.println(this.name + "正在吃饭");
    }

    public void bark(){
        System.out.println(this.name + "正在汪汪叫");
    }
}

class Cat{
    public String name;
    public int age;

    public void eat(){
        System.out.println(this.name + "正在吃饭");
    }

    public void bark(){
        System.out.println(this.name + "正在喵喵叫");
    }
}

public class New {
}

继承关键字和使用:?

? ? ? ?继承的关键字是extend,那么接下来我们就将这些共同的属性和方法进行抽取,并让其他的小类继承这个大类:

class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(this.name + "正在吃饭");
    }
}

class Dog extends Animal{
    public void bark(){
        System.out.println(this.name + "正在汪汪叫");
    }
}

class Cat extends Animal{
    public void bark(){
        System.out.println(this.name + "正在喵喵叫");
    }
}

public class New {
}

private修饰的父类:?

? ? ? ?子类会将父类的成员变量或者方法继承到子类去。被private修饰,也是可以被继承的,只是访问还是需要get和set方法,是否还记得那张图?

? ? ? ?因为是子类,不支持直接访问,所以还是要进行进行间接访问。

父类和子类用相同成员变量和方法:?

? ? ? ?我们来看以下代码:

class Base{
    public int a;
    public int b;
}

class Der extends Base{
    public int c;
    public void method(){
        a = 1;
        b = 2;
        c = 3;
    }
}

public class Test {
    Der d = new Der();
}

? ? ? ?此时父类和子类成员变量名不同。我们来看相同的情况。?

class Base{
    public int a = 20;
    public int b = 90;
}

class Der extends Base{
    public int a = 1;

    public void method(){
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

public class Test {
    public static void main(String[] args) {
        Der d = new Der();
        d.method();
    }
}

? ? ? ?也就是说,当父类和子类有相同变量成员时,优先看子类有有没有,没有再去父类中去找。所以成员变量和方法的访问遵循就近原则,自己有就限访问自己的,如果没有就去向父类中找。?

? ? ? ?此时调用方法也是一样的。

class Base{
    public void method() {
        System.out.println("Base::method()");
    }
}

class Der extends Base{
    public void method() {
        System.out.println("Der::method()");
    }
    public void method2() {
        System.out.println("Der::method()");
    }

    public void test() {
        method();
        method2();
    }
}

public class Test {
    public static void main(String[] args) {
        Der d = new Der();
        d.test();
    }
}

? ? ? ?当子类和父类中都有相同的成员和方法时,我们如果去使用方法就会使用子类中的方法,那么此时我们如何去使用父类中的成员或者方法呢??此时就需要用到super关键字了。

super关键字:?

super调用父类成员:

? ? ? ?当子类和父类中存在相同的成员变量和方法时,为了更好的区分,我们要使用super关键字。

class Base{
    int a = 99;
    public void method() {
        System.out.println("Base::method()");
    }
}
class Der extends Base{
    int a = 1;
    public void method() {
        System.out.println("Der::method()");
    }
    public void method2() {
        System.out.println("Der::method()");
    }
    public void test() {
        System.out.println(super.a);//使用super关键字访问父类成员
        super.method();//使用super关键字调用父类方法
        method2();
    }
}

public class Test {
    public static void main(String[] args) {
        Der d = new Der();
        d.test();
    }
}

? ? ? ?由此可见,super关键字是对标this的,我们来对比一下:

class Base{
    int a = 99;
}
class Der extends Base{
    int a = 1;
    public void test() {
        System.out.println(super.a);//使用super关键字访问父类成员
        System.out.println(this.a);
        System.out.println(a);
    }
}

public class Test {
    public static void main(String[] args) {
        Der d = new Der();
        d.test();
    }
}

super调用父类方法:

? ? ? ?和this的用法类似,可以使用super.方法。

class Base{
    public int a = 99;
    public void fun1(){
        System.out.println("hehe");
    }
}
class Der extends Base{
    public void fun2() {
        super.fun1();
    }
}
public class Test {
    public static void main(String[] args) {
        Der d = new Der();
        d.a = 99;
        d.fun2();
    }
}

成员初始化:

? ? ? ?有没有想过一个问题,就是如何将子类构造初始化?那么父类又是如何构造的?此时就需要知道super调用构造方法了。

super调用构造方法:

? ? ? ?因为写入了有参构造器,没有提供参数,所以报错。使用无参构造器则不报错。

? ? ? ?我们来观察子类继承了父类,父类成员如何初始化。子类在构造完成之前,一定要先帮助父类进行初始化。

? ? ? ?所以此时借助super来调用父类构造器。比如此时我们父类是有参构造器:

class Animal{
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println(this.name + "正在吃饭");
    }
}

class Dog extends Animal{
    public Dog() {
        super("远远",10);
    }

    public void bark(){
        System.out.println(this.name + "正在汪汪叫");
    }
}

? ? ? ?在此之前,我们没有写任何构造方法却编译通过了呢?还是一样的,它默认给了一个无参构造器(因为父类中也没有写构造器,父类中默认提供一个无参构造器,子类中默认体格一个无参构造器)。

//Dog类中的默认无参构造器
public Dog() {
    super();
    //只能有一个且必须在第一行
    //调用父类构造方法 帮助初始化 子类从 父类继承过来的成员 并不生成 父类对象
}

所以super有以下用法:

  • super.成员变量
  • super.成员方法
  • super()调用构造方法

this和super对标,也和以上一样。

? ? ? ?this针对当前对象;super针对当前对象的父类。

和this的共性:

? ? ? ?都只能在非静态方法中使用,在构造器中调用时,必须是构造方法中的第一条语句,且不能同时存在。

再谈初始化(结合代码块):

? ? ? ?还是否记得我们上一章节讲解的代码块的内容?那么接下来,我们就结合代码块来讲解在继承关系中是如何执行的。

class Animal{
    static {
        System.out.println("Animal::static");
    }
    public Animal() {
        System.out.println("Animal::构造");
    }

    {
        System.out.println("Animal::实例");
    }
}

class Dog extends Animal{
    static {
        System.out.println("Dog::static");
    }
    {
        System.out.println("Dog::实例");
    }
    
    public Dog() {
        super();
        System.out.println("Dog::构造");
    }
}

public class New {
    public static void main(String[] args) {
        Dog d = new Dog();
    }
}

? ? ? ?注意静态代码块最先执行且只执行一次。

protected性质和用法:

? ? ? ?看过我之前文章的小伙伴都知道了private和default(包权限修饰符)的用法和性质,通过以上的知识也就知道了父类和子类的关系。那么接下来我们就来具体讲解protected的性质和用法。

? ? ? ?我们先创建两个包,一个包是父类,另一个包继承父类(就是子类)。将父类的变量用protected修饰,此时直接访问报错。

? ? ? ?此时要用super访问。?

? ? ? ?依旧报错,此时是因为super和this不能再静态方法中使用,所以我们可以定义一个非静态方法。?

? ? ? ? 所以对于protected修饰的成员或者变量,不同包的子类可以访问。所以protected一般出现在继承当中,继承的父类一定是用public修饰的。

? ? ? ? 定义类时,只能用public,其余不行,否则报错。

final关键字:?

? ? ? ?我们先来看下面这张图:

? ? ? ?当继承到一定程度时,我们不想再继承时,就要使用final关键字了。?

? ? ? ?此时发现用final修饰的类不能在被继承,否则报错。所以final修饰的类也称密封类,表示当前类不能在被继承了。?

? ? ? ?因为java中没有const关键字,但是不代表没有常量,所以final也是常量修饰关键字。

? ? ? ?一般我们不希望出现多于3层的继承关系,所以要使用final关键字。

? ? ? ?final修饰方法:表示这个方法是密封方法,不能被重写。

文章来源:https://blog.csdn.net/weixin_64132124/article/details/135358946
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。