Java继承

简介: 各位朋友们,大家好!今天我为大家分享的是Java上面一个很重要的知识点:继承,继承也被称为Java的灵魂之一。

为什么要使用继承


在生活中,我们都见过猫和狗这两种动物吧,我们都知道Java是一种面向对象的语言,我们可以创建出任何我们想要的对象,那么如果我们想要用Java来创建出猫和狗该怎么办呢?在创建之前我们首先得知道猫和狗有什么特性。我们都知道猫和狗都有名字、体重、身高,都会吃饭、睡发出叫声,那么我们可以通过创建类将他们的特性包含在内。


//猫
class Cat {
    String name;
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
    public void bark(){
    System.out.println(name+"汪汪汪~~~");
  }
}
//狗
class Dog {
    String name;
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"正在睡觉");
    }
    public void bark(){
    System.out.println(name+"喵喵喵~~~");
  }
}


当我们看到两个类的时候,我们可能会发现问题:那就是这两个代码中有很多重复的成员变量,那么如果我们要想大大降低代码的复用率该怎么办呢?这里最好的解决方法就是使用我们所说的继承,因为猫和狗都属于动物,我们可以将猫和动物以及其他类型的动物的共性都给提出来作为父类,子类只需要继承父类就可以拥有父类所具有的特性。


//Animal作为父类具有子类的共特性
class Animal {
    String name;
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
}

子类怎样继承父类


我们子类要想继承父类,我们需要用到extends这个关键字。格式是

class 子类类名 extends 父类类名{}

所以我们上面的代码可以简化成这样:

class Animal {
    String name;
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
}
class Cat extends Animal{
    public void bark(){
    System.out.println(name+"汪汪汪~~~");
  }
}
class Dog extends Animal{
    public void bark(){
    System.out.println(name+"喵喵喵~~~");
  }
}

而猫和狗的内存分配大概是这样的。


在子类中如何访问父类的成员


一般在子类中我们可以直接访问父类的成员变量。就像这样:

class Animal {
    String name = "Animal";
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
}
class Cat extends Animal{
    public void Method() {
        System.out.println(name);
    }
    public void Bark() {
        System.out.println(name+"喵喵喵~~~");
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat  =new Cat();
        cat.Method();
    }
}

18.png

这种是子类和父类没有相同的成员变量,如果子类和父类有相同的成员变量时,我们访问的又是谁的成员变量呢?

class Animal {
    String name = "Animal";
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
}
class Cat extends Animal{
    String name = "大黄";
    public void Method() {
        System.out.println(name);
    }
    public void Bark() {
        System.out.println(name+"喵喵喵~~~");
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat  =new Cat();
        cat.Method();
    }
}

19.png

我们可以看到这里他访问的是子类自己拥有的成员,也就是说在这里遵守就近原则,方法也是如此。

class Animal {
    String name = "Animal";
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
    public void Method1() {
        System.out.println("this is Animal's Method");
    }
}
class Cat extends Animal{
    String name = "大黄";
    public void Method() {
        System.out.println(name);
    }
    public void Method1() {
        System.out.println("this is Cat's Method");
    }
    public void Bark() {
        System.out.println(name+"喵喵喵~~~");
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat  =new Cat();
        cat.Method1();
    }
}

20.png

那么如果我们想在子类中访问相同的成员的父类的成员该怎么办呢?


super关键字


我们需要用到super这个关键字来访问父类中与子类具有相同名字的成员。

class Animal {
    String name = "Animal";
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
    public void Method1() {
        System.out.println("this is Animal's Method");
    }
}
class Cat extends Animal{
    String name = "大黄";
    public void Method() {
        System.out.println(name);
    }
    public void Method1() {
        System.out.println("this is Cat's Method");
    }
    public void Method2() {
        System.out.println(super.name);
    }
    public void Bark() {
        System.out.println(name+"喵喵喵~~~");
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat  =new Cat();
        cat.Method2();
    }
}

21.png

我们也可以用super来访问父类的方法。

class Animal {
    String name = "Animal";
    float weight;
    float hight;
    public void Eat() {
        System.out.println(name+"正在吃");
    }
    public void Sleep() {
        System.out.println(name+"在睡觉");
    }
    public void Method1() {
        System.out.println("this is Animal's Method");
    }
}
class Cat extends Animal{
    String name = "大黄";
    public void Method() {
        System.out.println(name);
    }
    public void Method1() {
        System.out.println("this is Cat's Method");
    }
    public void Method2() {
        System.out.println(super.name);
    }
    public void Method3() {
        Method1();
        super.Method1();
    }
    public void Bark() {
        System.out.println(name+"喵喵喵~~~");
    }
}
public class Main {
    public static void main(String[] args) {
        Cat cat  =new Cat();
        cat.Method3();
    }
}

image.png


当父类中有构造方法时


当我们的父类中有构造方法时,我们在构造子类的时候需要在构造方法的第一行使用super(),来先帮助父类完成构造,然后再完成自己的构造方法。

class Base {
    public Base() {
        System.out.println("Base");
    }
}
class Derived extends Base{
    public Derived() {
        super();
        System.out.println("Derived");
    }
}
public class Main {
    public static void main(String[] args) {
        Derived deriver = new Derived();
    }
}

23.png

不仅如此我们都知道如果你的类中没有构造方法,编译器会默认帮你生成一个无参的构造方法,如果你的类中还有继承关系,那么在构造方法的第一行还会默认有super()。

class Base {
    public Base() {
        System.out.println("Base");
    }
}
class Derived extends Base{
}
public class Main {
    public static void main(String[] args) {
        Derived deriver = new Derived();
    }
}

image.png

但是如果你的父类中有有参数的构造方法,你就必须先帮助父类完成构造,否则编译器会报错。

image.png

image.png

this关键字


我们在实例化一个类时,往往是先完成这个类具有的构造方法,而构造方法往往是给类的成员变量赋值的,那么我们怎样通过构造方法给成员变量赋值呢?


这里就需要this,this代表当前类实例的一个引用,它可以在构造器、成员方法和代码块中使用,表示当前类的实例对象。

class Base {
    String name;
    public Base(String name) {
        this.name = name;
        System.out.println(name);
    }
}
class Derived extends Base{
    public Derived() {
        super("大黄");
    }
}
public class Main {
    public static void main(String[] args) {
        Derived deriver = new Derived();
    }
}

27.png

this的功能不止这些,我们都知道方法可以发生重载,构造方法也是如此。

我们可以使用this(),来完成该类中的其他的构造方法。

class Base {
    String name;
    int age;
    public Base(String name) {
    //完成该类中带有两个参数的构造方法
        this(name,0);
        this.name = name;
        System.out.println(name);
    }
    public Base(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println(name+age);
    }
}
class Derived extends Base{
    public Derived() {
        super("大黄");
    }
}
public class Main {
    public static void main(String[] args) {
        Derived deriver = new Derived();
    }
}

image.png

但是这里我们需要注意的是this()跟super()一样,都必须放在构造方法的第一行,也就是说super()和this()不能同时出现。


初始化

class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("构造方法执行");
    }
    {
        System.out.println("实例代码块执行");
    }
    static {
        System.out.println("静态代码块执行");
    }
}
public class Main {
    public static void main(String[] args) {
        Person person1 = new Person("zhangsan",10);
        System.out.println("===========================");
        Person person2 = new Person("lisi",18);
    }
}


我们看看这段代码的结果是什么?


image.png


通过这段代码我们可以知道静态代码块、实例代码块和构造方法的执行顺序是:先执行静态代码块,然后是实例代码块,最后是构造方法,并且静态代码块只会执行一次。


那么如果有继承关系的时候执行顺序又是怎样的呢?

class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person:构造方法执行");
    }
    {
        System.out.println("Person:实例代码块执行");
    }
    static {
        System.out.println("Person:静态代码块执行");
    }
}
class Student extends Person{
    public Student(String name,int age) {
        super(name,age);
        System.out.println("Student:构造方法执行");
    }
    {
        System.out.println("Student:实例代码块执行");
    }
    static {
        System.out.println("Student:静态代码块执行");
    }
}
public class Main {
    public static void main(String[] args) {
        Student student1 = new Student("zhangsan",19);
        System.out.println("===========================");
        Student student2 = new Student("lisi",20);
    }
}

30.png


也就是说先执行父类的静态代码块,然后是子类的静态代码块,然后是父类的实例代码块,父类的构造方法,最后是子类的实例代码块和构造方法。


protected关键字


我们的子类是否可以访问父类的所有成员呢?其实并不是。


31.png


我们可以看到这里的c是不能被访问的,因为父类的c被private修饰的,他只能在当前类中使用,那么如果我们只让父类的子类使用的成员该怎么办呢?我们可以使用protected。


image.png


你其他的没有继承父类的类就不能使用被protected修饰过的成员,这样大大提高了代码的安全性。


33.png

final关键字

如果我们的类不想被继承,我们可以在类的前面加上final修饰,代表他是最终类,该类不可被继承。final修饰变量表明该变量不可被改变,他的属性也就从变量变成了常量。final修饰方法,表明这个方法不可被重写,重写我们后面再讲。


建议

在Java中继承是一个非常实用的特性,我们应该正确的使用它。继承关系可以有很多层,但是不建议超过三层,并且在Java中不可以多继承,也就是说一个类不能继承多个类,就像一个儿子不能有多个父亲一样,父类可以有多个子类。

相关文章
|
27天前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
4天前
|
Java 编译器
Java——类与对象(继承和多态)
本文介绍了面向对象编程中的继承概念,包括如何避免重复代码、构造方法的调用规则、成员变量的访问以及权限修饰符的使用。文中详细解释了继承与组合的区别,并探讨了多态的概念,包括向上转型、向下转型和方法的重写。此外,还讨论了静态绑定和动态绑定的区别,以及多态带来的优势和弊端。
19 9
Java——类与对象(继承和多态)
|
29天前
|
Java C++
【Java基础面试十七】、Java为什么是单继承,为什么不能多继承?
这篇文章讨论了Java单继承的设计原因,指出Java不支持多继承主要是为了避免方法名冲突等混淆问题,尽管Java类不能直接继承多个父类,但可以通过接口和继承链实现类似多继承的效果。
【Java基础面试十七】、Java为什么是单继承,为什么不能多继承?
|
8天前
|
Java
java的继承详解
在 Java 中,继承是一个核心概念,它允许子类 `extends` 父类来重用和扩展其属性与方法。子类可以覆盖父类的方法以改变行为,同时使用 `super` 关键字调用父类的构造方法或方法。虽然 Java 不支持多继承,但可以利用抽象类与接口实现多层继承。这种方式极大地增强了代码的复用性和维护性。
|
21天前
|
Java 编译器
Java继承
Java继承
13 1
|
1月前
|
Java
Java 新手入门:Java 封装、继承、多态详解
Java 新手入门:Java 封装、继承、多态详解
31 1
|
28天前
|
Java
【Java基础面试四十二】、 static修饰的类能不能被继承?
这篇文章讨论了Java中static关键字修饰的类是否可以被继承,解释了静态内部类的概念、规则以及如何实例化。
|
1月前
|
Java 编译器
【Java】继承
【Java】继承
|
2月前
|
Java 程序员
【Java探索之旅】继承概念_语法_父类的成员访问
【Java探索之旅】继承概念_语法_父类的成员访问
42 10
|
2月前
|
安全 Java 开发者
Java面试题:什么是Java 15中的密封类以及其限制?还有哪些其他特性用于限制类继承的机制吗?
Java面试题:什么是Java 15中的密封类以及其限制?还有哪些其他特性用于限制类继承的机制吗?
27 1