Java继承全攻略

简介: Java继承全攻略

哈喽,我是兔哥呀,今天就让我们继续这个JavaSE成神之路!

这一节啊,咱们要学习的内容是Java的继承。


1.什么是继承

还是从现实中的例子出发,比如人和学生,学生属于人,每个学生都有姓名和年龄,人也拥有这些共通的属性,那么我们就可以说学生继承自人。


2.继承的实现

java继承是面向对象编程中一种基本概念,可以让子类继承父类的属性和方法,提高代码的复用性。

例如:


public class Person {
    private String name;
    private int age;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
    public int getAge(){
        return age;
    }
    public void setAge(int age){
        this.age = age;
    }
}
public class Student extends Person {
    private String school;
    public String getSchool(){
        return school;
    }
    public void setSchool(String school){
        this.school = school;
    }
}

继承需要使用extends关键字。


上面的代码中,Student类继承了Person类,Student类继承了Person类的name和age属性,以及getName()和setName()方法,同时还定义了school属性和getSchool()方法。


在这个例子中,Person是被继承的类,叫做父类或超类。而Student是继承后的类,叫做子类或者派生类。


3.继承的关系


在开发中,比如有学生类和老师类,他们有一些公共的属性,比如名字、年龄等,那么我们就可以提取一个公共的逻辑意义上的父类-人类。


所以,继承是 is a 的关系,学生是人,老师也是人,这样的情况下就可以生成一个逻辑父类 - Person,然后把学生类和老师类都去继承Person,实现属性和方法的复用。


4.方法的重写

Java方法重写是指在子类中重新定义父类中的方法,覆盖父类中的方法,使之成为子类的方法。


简单来说,就是子类的方法覆盖了父类的相同方法。


在开发中,使用方法重写可以让子类具有父类的特性,同时又能够根据自身的需要进行扩展,从而更加灵活地处理业务逻辑。


方法重写也是多态的一种表现形式,它可以让我们调用同一接口,却能够根据不同的实现类,调用不同的实现方法,实现不同的业务逻辑。


比如上面的例子,Person类中有一个sayHello方法:

public void sayHello(){
    System.out.println("Hello, I am a person!");
}

子类又把sayHello重新定义了一遍,就是方法重写。

public void sayHello(){
    System.out.println("Hello, I am a student!");
}

如下图,idea中对于重写的方法,有一个向上箭头的标志,点一下就能进入父类的同名方法。

2.png


5.方法重写的返回值问题

这边就是要记住一个规律啦,当父类方法的返回值是void或者基本数据类型时,子类的重写方法的返回值必须和父类方法完全一致。


当父类方法的返回值是引用类型时,子类的重写方法的返回值可以是父类的其他子类引用。


验证一下,父类Person有一个getAge方法,我们试着重写这个方法。


//这是父类Person的getAge方法
public int getAge(){
    return age;
}
//这是子类的getAge方法,返回值改了
public double getAge(){
    return 1.0;
}

报错了:

3.png


'getAge()' in 'com.company.dto.Student' clashes with 'getAge()' in 'com.company.dto.Person'; attempting to use incompatible return type


所以,如果是基本数据类型,方法重写我们不能修改返回值。


父类增加一个返回值是Person的方法:

public Person getInstance(){
    return new Person();
}

我们再创建一个老师类,重写父类的getInstance,同时把返回值改成自己。

public Teacher getInstance() {
    return new Teacher();
}

如下图,这是允许的。

4.png

你改成另一个子类引用也可以。

5.png


6.方法重写的方法重载的区别

方法重写要求子类方法的参数列表必须与父类方法的参数列表完全相同,返回值类型也必须完全相同(返回值如果是引用类型则向下兼容,参考上一节);

而方法重载仅要求子类方法的参数个数类型不同,而返回值类型可以相同也可以不同。


7.属性可以重写吗

答案是可以的,子类可以重复定义父类的同名属性,到时候使用的就是子类的属性啦。


8. 访问修饰符

Java的权限访问修饰符是用来控制类、接口、变量、方法的访问权限的,它有四种:public、protected、default和private。


8.1 private

private代表私有的,只能在本类中访问,其他任何地方都不能访问,包括子类。

证明:

这个name是private修饰的:

6.png

然后在子类中:

7.png

连子类中都无法访问,其他地方就都不必说了吧。哪怕你在其他地方把Person类new一个对象除了,都无法直接访问里面的private属性,对象也不行哦。

8.png

所以,private的访问权限是最严格的。


8.2 public

public代表公有的,在任何地方都能访问,不管跨不跨包,是不是子类,public和private就是两个极端。


8.3 protected

protected代表受保护的,允许当前类同包下的任意类,以及跨包子类调用。就这3个,没多的了,记好就行。


8.4 default(就是啥也不写)

啥权限修饰符都不写,代表默认访问权限,允许当前类同包下的任意类调用。和protected的区别就是少一个跨包子类调用。

访问权限从小到大是:

private < default < protected < public

记住就行了,非常重要哈。


9.访问修饰符对方法重写的影响(大于等于父类的权限)

方法重写要求子类方法的访问权限不能低于父类方法的访问权限,即子类方法的访问权限可以和父类方法的访问权限相同,也可以更高,但不能更低。

为什么会这样呢,其实也是来源于生活,父母都希望自己的孩子超越自己,所谓望子成龙,望女成凤啊。


10. super关键字

super关键字是Java语言中的一个关键字,它的作用是调用超类中的成员变量和方法,也就是父类的成员变量和方法。

public class Person {
    protected double money = 10000; //留给孩子1w买糖吃
    ... ...
}


给父类添加一个protected的money属性,子类重写这个属性。

public class Student extends Person {
    protected double money;
    public double getMoney() {
        return money;
    }
    ... ...
}

测试:

public static void main(String[] args) {
    Student s = new Student();
    System.out.println(s.getMoney());
}

结果是0.0,这是因为Student重写了money属性,所以访问的就是自己的money,要访问到父类的money,我们可以用super:

public double getMoney() {
    return super.money;
}

这样拿到的就是1w啦。

super关键字也可以用来调用超类的构造方法,这样可以在子类的构造方法中调用超类的构造方法,从而实现继承。

我们给父类Person添加一个空构造:

public Person(){
    System.out.println("Person类的构造方法被调用");
    this.money = 20000;
}

子类调用方式如下:

public Student() {
    super(); //调用父类的构造方法
}

再测试:

public static void main(String[] args) {
    Student s = new Student();
    System.out.println(s.getMoney());
}

打印:


Person类的构造方法被调用


20000.0


注意:构造方法是没办法被子类重写的。每一个子类对象被创建,都会先去调用父类的构造方法,如果没有显式地用super去指定调用父类的哪个构造方法,就会默认调用父类的无参构造方法。如果你在父类写了一个有参构造方法,但没有写无参构造方法,那么子类的构造方法就会报错。


比如,你在Person类中写了一个有参构造,却没有定义无参构造。

public Person(double money){
    System.out.println("Person类的构造方法被调用");
    this.money = money;
}


那么子类不管你有没有写无参构造都会报错:

9.png

错误信息:There is no default constructor available in 'com.company.dto.Person'


解决办法,要么你显示地给Person添加无参构造,要么每个子类都要显示地用super去调用一下那个有参构造。


就算是工作好几年的老码农,也常常会在这个地方犯迷糊,这一点也要尤其注意哦!


总之,super关键字是Java语言中的一个关键字,它的作用是调用超类中的成员变量和方法,也可以用来调用超类的构造方法,从而实现继承。


10. super关键字 和 this关键字

1、super引用的是超类对象,this引用的是本类对象。

super可以在子类中调用超类中的成员,而this只能在本类中调用本类中的成员。

2、对于那些从父类继承的成员属性和成员方法,this和super访问的是同一个。

如:

public class Person {
    protected double money = 10000; //留给孩子1w买糖吃
    ... ...
}

子类中:

public Student() {
    System.out.println(this.money == super.money);
}

因为money已经被继承下来了,所以用this访问也是可以的。

4. 不管是this还是super,都不能出现在static方法中。


11.课后练习

Q:已知有Object类、A类和B类,其中A类继承Object类,B类继承A类,以下哪个语句是正确的?

A. B类的父类是Object

B. A类的父类是B类

C. B类的父类是A类

D. Object类的父类是A类

相关文章
|
3月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
24天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
19 3
|
24天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
33 2
|
24天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
24天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
2月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
1月前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第4天】Java零基础教学篇,手把手实践教学!
34 2
|
1月前
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
21 5
|
1月前
|
Java
java继承和多态详解
java继承和多态详解
42 5
|
1月前
|
Java 编译器
【一步一步了解Java系列】:子类继承以及代码块的初始化
【一步一步了解Java系列】:子类继承以及代码块的初始化
24 3