JAVA系列 小白入门参考资料 继承

发布于:2024-04-30 ⋅ 阅读:(31) ⋅ 点赞:(0)

目录

1. 为什么需要继承

2. 继承的概念

3. 继承的语法

4. 父类成员访问 

        4.1 子类中访问父类的成员变量

                  1. 子类和父类不存在同名成员变量

                  2.  子类和父类成员变量同名  

4.2 子类中访问父类的成员方法 

1. 成员方法名字不同

2. 成员方法名字相同  

​5. super关键字

6. 子类构造方法

7. super和this  

相同点

不同点

8. 继承关系的执行顺序

9. 继承方式 

单继承

多层继承 

不同类继承同一个类 

10. final关键字


1. 为什么需要继承

Java 中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联。因此需要一些程序设计来解决这个问题。
下面通过代码来发现问题
//定义一个狗类
class Dog{
    public String name;
    public int age;
    public String color;


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

    public void run() {
        System.out.println(this.name + "在跑");
    }
}

//定义一个鸟类
class Bird{
    public String name;
    public int age;
    public String color;


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

    public void fly() {
        System.out.println( this.name + "在飞");
    }
}

public class blog {


    public static void main(String[] args) {
        Dog dog = new Dog(); //创建对象
        //初始化
        dog.name = "小灰";
        dog.age = 10;
        dog.color = "灰色";
        //调用方法
        dog.eat();
        dog.run();


        Bird bird = new Bird();
        bird.name = "小花";
        bird.age = 10;
        bird.color = "花色";
        bird.eat();
        bird.fly();


    }
}

我们可以看到Dog类和Bird类中有以下相同的成员变量和成员方法

    public String name;
    public int age;
    public String color;


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

因此 我们为了节省代码,提高代码的复用性,我们引入了继承这个概念。

2. 继承的概念

继承 (inheritance) 机制 :是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性
的基础上进行 扩展,增加新功能 ,这样产生新的类,称 派生类 。继承呈现了面向对象程序设计的层次结构, 体现了
由简单到复杂的认知过程。继承主要解决的问题是: 共性的抽取,实现代码复用

3. 继承的语法

修饰符 class 子类 extends 父类 {
      // ...
}
关键字是 extends

因为 小狗和小鸟 都是属于动物,他们有自己的年龄、颜色等等属性。也会吃东西等等相同动作,并且作为宠物都会给他们给予名字 。

因此 我们创建一个新的类(Animals) 作为父类,并将 这些相同的属性和动作作为成员变量和成员方法  放入其中。

以下代码为使用继承之后。我们可以明显的看到 代码少了很多。

并且在现实生活中我们只需要关注子类特有的属性和方法即可

class Animals{
    public String name;
    public int age;
    public String color;


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

class Dog extends Animals{
    public void run() {
        System.out.println(this.name + "在跑");
    }
}

class Bird extends Animals{
    public void fly() {
        System.out.println( this.name + "在飞");
    }
}

public class blog {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "小灰";
        dog.age = 10;
        dog.color = "灰色";
        dog.eat();
        dog.run();

        Bird bird = new Bird();
        bird.name = "小花";
        bird.age = 10;
        bird.color = "花色";
        bird.eat();
        bird.fly();
    }
}

4. 父类成员访问 

4.1 子类中访问父类的成员变量

        1.子类和父类不存在同名成员变量
class Father {
    public int a = 10;
    public int b = 20;
}

class Son extends Father {
    public int c = 30;
    public void Method(){
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}


public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.Method();
    }
}

程序正常运行,并且子类可以访问父类的成员变量,并打印值。 

2. 子类和父类成员变量同名  

使用关键字 super

我们先来看 如果  子类和父类成员变量同名 会输出什么?

class Father {
    public int a = 10;
    public int b = 20;
}

class Son extends Father {
    public int a = 100;  // 如果子类有  先访问子类的。  子类没有的  才会去看父类是否有
    public int c = 30;   
    public void Method(){
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}


public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.Method();
    }
}

由此我们可知,会输出子类的 同名成员变量。

那么如果我们非要访问 父类变量呢?

就是前面所提的 super 

class Father {
    public int a = 10;
    public int b = 20;
}

class Son extends Father {
    public int a = 100;
    public int c = 30;
    public void Method(){
        System.out.println(super.a);// 输出父类的 a
        System.out.println(this.a);// 谁调用 就输出谁的a 
        System.out.println(b);
        System.out.println(c);
    }
}


public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.Method();
    }
}

在子类方法中 或者 通过子类对象访问成员时
1.如果访问的成员变量子类中有,优先访问自己的成员变量。
2.如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
3.如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找

4.2 子类中访问父类的成员方法 

1. 成员方法名字不同

class Father{
    public void Func() {
        System.out.println("Func");
    }
}

class Son extends Father{
    public void Func2() {
        System.out.println("Func2");
    }

    public void Func3() {
        Func();
        Func2();
    }
}

public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.Func3();
    }
}

2. 成员方法名字相同  

 我们在Son类中添加一个   和 Father类一模一样Func成员方法,看结果如何?

class Father{
    public void Func() {
        System.out.println("Func");
    }
}

class Son extends Father{
    public void Func() {
        System.out.println("Son::Func");
    }

    public void Func2() {
        System.out.println("Func2");
    }

    public void Func3() {
        Func();
        Func2();
    }
}

public class Test {
    public static void main(String[] args) {
        Son son = new Son();
        son.Func3();
    }
}

结果是 子类有同名方法,先调用自己的方法。 

如果想要在子类调用 父类中的同名成员方法,还是需要用到关键字super

//在此就不过多 赘写代码了 
//基于上面的代码
//这里我将最核心的代码修改部分,单提了出来
 
public void Func3() {
        this.Func();
        super.Func();
        this.Func2();
    }

5. super关键字

作用:在子类方法中访问父类的成员。

如何使用,前面代码已经展示了其作用。

注意事项:
1. 只能在非静态方法中使用
2. 在子类方法中,访问父类的成员变量和方法。 

6. 子类构造方法

父子,即先有父,后有子。所以在我们的代码中,当我们想创建子类对象时,要先调用和实现父类的构造方法,然后再实现子类构造方法 

在之前的代码中,虽然父类和子类都没有显式的定义构造方法。但其实 子类中 有隐藏的代码

public class Father {
    public Father(){
    System.out.println("Father()");
    } 
}

public class Son extends Father{
    public Son(){
    // super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
    // 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
    // 并且只能出现一次
    System.out.println("Son()");
  }
}

下面代码是父类已经有定义好的构造方法

class Animals{
    public String name;
    public int age;
    public String color;

    //父类的构造方法
    public Animals(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

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

class Dog extends Animals {

    //子类的构造方法
    public Dog() {
        super("小罗",10,"白色");
    }

    public void run() {
        System.out.println(this.name + "在跑");
    }
}

class Bird extends Animals {

    //子类的构造方法
    public Bird(String name, int age, String color) {
        super(name, age, color);
    }

    public void fly() {
        System.out.println( this.name + "在飞");
    }
}


public class Blog {
    public static void main(String[] args) {
        Dog dog = new Dog();// 根据构造方法   
        //第一种初始化方式
        dog.name = "小灰";
        dog.age = 10;
        dog.color = "灰色";
        dog.eat();
        dog.run();

        Bird bird = new Bird("小辣椒",10,"红色");// 根据构造方法  //第二种初始化方法
        bird.eat();
        bird.fly();
    }
}

注意:

1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现

7. superthis  

super  和  this  都可以在成员方法中用来访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那他们之间有什么区别呢?

相同点

1. 都是Java中的关键字
2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
3. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

不同点

1. this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
3. 在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造 方法中出现
4. 构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有

8. 继承关系的执行顺序

在之前的学习中我们知道了

1.静态代码块先执行,并且只执行一次,在类加载阶段执行

2.当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行

class Persons{
    String name;
    int age;

    public Persons(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person构造方法被调用");
    }

    {
        System.out.println("Person实例代码块被调用");
    }

    static {
        System.out.println("Person静态代码块被调用");
    }
}

class Students extends Persons{
    public Students(String name, int age) {
        super(name, age);
        System.out.println("Students构造方法被调用");
    }

    {
        System.out.println("Students实例代码块被调用");
    }

    static {
        System.out.println("Students静态代码块被调用");
    }

}

public class job {
    public static void main(String[] args) {
        Students students = new Students("小罗",18);
        Students students2 = new Students("小米",18);
    }
}

无奖竞猜:大家猜一下输出结果是什么?

通过分析执行结果,得出以下结论
1、父类静态代码块优先于子类静态代码块执行,且是最早执行
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行

9. 继承方式 

单继承

多层继承 

 不同类继承同一个类 

 最重要的是,不可以同一个类继承不同的类

10. final关键字

final关键可以用来修饰变量、成员方法以及类。

1.修饰变量或字段,表示常量(即不能修改)

2.修饰类:表示此类不能被继承

3.修饰方法:表示该方法不能被重写 


网站公告

今日签到

点亮在社区的每一天
去签到