Java中的重要核心知识点之继承详解

目录
  • 一、继承
    • 1、概念
    • 2、语法
    • 3、父类成员的访问
      • (1)子类中访问父类成员变量
      • (2)子类中访问父类成员方法
    • 4、super关键字
    • 5、子类构造方法
    • 6、super和this
    • 7、代码块执行顺序
    • 8、父类成员在子类中的可见性
    • 9、继承方式
    • 10、final关键字
    • 11、组合

一、继承

1、概念

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

例如:狗和猫都是动物,分别定义一个猫类和狗类,他们都是动物,让他们来继承动物类,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。

// Dog.java
public class Dog{
string name;
int age;
float weight;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}
void Bark(){
System.out.println(name + "汪汪汪~~~");
}
}
// Cat.Java
public class Cat{
string name;
int age;
float weight;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep()
{
System.out.println(name + "正在睡觉");
}
void mew(){
System.out.println(name + "喵喵喵~~~");
}
}

2、语法

在Java中如果要表示类之间的继承关系,需要借助extends关键字,具体如下:

修饰符 class 子类 extends 父类 {
// ...
}

那么对于猫和狗的场景,我们让猫类和狗类均继承自动物类:

public class Animal{
String name;
int age;
public void eat(){
System.out.println(name + "正在吃饭");
}
public void sleep(){
System.out.println(name + "正在睡觉");
}
}
// Dog.java
public class Dog extends Animal{
void bark(){
System.out.println(name + "汪汪汪~~~");
}
}
// Cat.Java
public class Cat extends Animal{
void mew(){
System.out.println(name + "喵喵喵~~~");
}
}
// TestExtend.java
public class TestExtend {
public static void main(String[] args) {
Dog dog = new Dog();
// dog类中并没有定义任何成员变量,name和age属性肯定是从父类Animal中继承下来的
System.out.println(dog.name);
System.out.println(dog.age);
// dog访问的eat()和sleep()方法也是从Animal中继承下来的
dog.eat();
dog.sleep();
dog.bark();
}
}

注意事项:
1、子类会将父类中的成员变量或成员方法继承到子类中去。
2、子类中一定要含有与父类不同的成员方法或者成员变量,体现出与父类的不同,否则继承就失去了意义。

3、父类成员的访问

(1)子类中访问父类成员变量

第一种情况:子类和父类不存在同名成员变量

public class Base {
    int a;
    int b;
}
public class Derived extends Base {
    int c;
    int d;

    public void method(){
        a=10;//访问的是从父类继承下来的成员变量a
        b=20;//访问的是从父类继承下来的成员变量b
        c=30;//访问的是子类自己的成员变量c
        d=40;//访问的是子类自己的成员变量d
    }
}

第二种情况:子类和父类成员变量有同名

public class Base {
    int a;
    int b;
}
public class Derived extends Base {
    int b;
    int c;

    public void method(){
        a=10;
        b=20;//此时访问的是父类中的b还是子类中的b?
        c=30;
        //d=40; 编译报错,因为在子类和父类中都不存在成员变量d
    }
}

注意事项:
在子类方法中或者通过子类对象访问成员变量时:
1、如果访问的成员变量子类中有,优先访问自己的成员变量。
2、如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
3、如果访问的成员变量与父类中成员变量同名,则优先访问自己的,即:子类将父类同名成员隐藏了。

(2)子类中访问父类成员方法

第一种情况:子类和父类中不存在同名成员方法

public class Base {
    public void methodA(){
        System.out.println("我是父类成员方法");
    }
}
public class Derived extends Base {
    public void methodB(){
        System.out.println("我是子类成员方法");
    }

    public void methodC(){
        methodA();//访问继承自父类成员方法
        methodB();//访问子类自己的成员方法
        //methodD(); 编译报错,在继承体系中没有methodD方法
    }
}

第二种情况:子类和父类中存在同名方法

public class Base {
    public void methodA(){
        System.out.println("我是父类成员方法methodA");
    }
    public void methodB(){
        System.out.println("我是父类成员方法methodB");
    }
}
public class Derived extends Base {
    public void methodA(int a){
        System.out.println("我是子类成员方法methodA");
    }

    public void methodB(){
        System.out.println("我是子类成员方法methodB");
    }

    public void methodC(){
        methodA(1);//带参的methodA方法,访问的是子类的方法
        methodA();//无参的methodA方法,访问的是父类的方法
        methodB();//直接访问methodB,访问到的是子类的方法
    }
}

注意事项:
1、通过子类对象或方法访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。
2、通过子类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同,根据调用方法时传递的参数选择合适的方法访问,如果没有则报错;如果父类和子类同名方法的原型一致,则只能访问到子类的,父类的无法通过派生类对象直接访问到。

咦????那么问题来了,如果想要访问与子类方法同名且原型一致的父类方法时该怎么访问呢?——super关键字

4、super关键字

当子类和父类中存在同名且原型一致的方法时,我们想要调用父类的该方法时发现不能直接访问,而在Java中提供了super关键字,该关键字的主要作用就是:在子类方法中访问父类成员。

public class Base {
    int a;
    int b;

    public void methodA(){
        System.out.println("我是父类成员方法methodA");
    }
    public void methodB(){
        System.out.println("我是父类成员方法methodB");
    }
}
public class Derived extends Base {
    int a;//与父类同名成员
    String b;//与父类同名成员的类型不同

    // 与父类中methodA()构成重载
    public void methodA(int a){
        System.out.println("我是子类成员方法methodA");
    }
    //重写父类中的methodB方法
    public void methodB(){
        System.out.println("我是子类成员方法methodB");
    }

    public void methodC(){
        a=100;
        super.a=110;
        b="abc";
        super.b=100;

        methodA(1);//带参的methodA方法,访问的是子类的方法
        methodA();//无参的methodA方法,访问的是父类的方法
        methodB();//直接访问methodB,访问到的是子类的方法
        super.methodB();//通过super关键字调用的是父类的methodB
    }
}

注意事项:

1、只能在非静态方法中使用。

2、用于在子类方法中,访问父类的成员变量和方法。

5、子类构造方法

子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

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

    public static void main(String[] args) {
        Derived a=new Derived();
    }
}

/*
执行结果
我是父类构造方法
我是子类构造方法
*/

说明:在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法,因为:子类对象是一个父类对象,在构造子类对象时,先要将从父类继承下来的成员初始化完整,然后再初始化子类自己新增加的成员。
从对象模型的角度来看:

注意事项:
1、若父类显式定义无参或者默认的构造方法,编译器会给子类生成一个默认的构造方法,且在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法。
2、如果父类构造方法是带有参数的,此时编译器不会再给子类生成默认的构造方法,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
具体看如下代码:

public class Base {
    int a;
    int b;
   public Base(int a){ //父类中带参数的构造方法
       this.a=a;
   }
}
public class Derived extends Base {
    public Derived(int a,int b){ //此时需要在子类中自定义构造方法
        super(a);//选择合适的父类构造方法调用
        this.b=b;
    }

    public static void main(String[] args) {
        Derived a=new Derived(10,20);
        System.out.println(a.a);
        System.out.println(a.b);
    }
}

/*
执行结果:
10
20
*/

3、在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句。
4、super(…)只能在子类构造方法中出现一次,并且不能和this同时出现。

6、super和this

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

不同点:
先给一段代码

public class Base {
    int a;
    int b;
}
public class Derived extends Base {
    int c;
    int d;
    public void method(){
        super.a=10;
        super.b=20;

        this.c=30;
        this.d=40;
    }
    public static void main(String[] args) {
        Derived d=new Derived();
        d.method();
    }
}

1、 this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是父类对象的引用。针对上述代码,如下图所示:

2、在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。上图也可以进行说明。
3、this是非静态成员方法的一个隐藏参数,super不是隐藏的参数。还是针对上述代码,从字节码的角度来看,打开method方法中的局部变量表,发现只有this,而没有super。

4、成员方法中直接访问本类成员时,编译之后会将this还原,即本类非静态成员都是通过this来访问的;在子类中如果通过super访问父类成员,编译之后在字节码层面super实际是不存在的。

5、在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造方法中出现。
6、 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有。

7、代码块执行顺序

第一种:在没有继承关系时的执行顺序

public class Person {
    int age;
    String name;

    public Person(int age,String name){
        this.age=age;
        this.name=name;
        System.out.println("执行构造方法");
    }
    {
        System.out.println("执行实例代码块");
    }

    static {
        System.out.println("执行静态代码块");
    }

    public static void main(String[] args) {
        Person a=new Person(20,"luka");
        System.out.println("-----------------------");
        Person b=new Person(21,"stepth");
    }
}

/*
执行结果:
执行静态代码块
执行实例代码块
执行构造方法
-----------------------
执行实例代码块
执行构造方法
*/

说明:
1、静态代码块先执行,并且只执行一次,在类加载阶段执行
2、 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行
第二种:在存在继承关系时的执行顺序

public class Person {
    int age;
    String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
        System.out.println("Person:执行构造方法");
    }

    {
        System.out.println("Person:执行实例代码块");
    }

    static {
        System.out.println("Person:执行静态代码块");
    }
}
public class Student extends Person{
    public Student(int age,String name){
        super(age,name);
        System.out.println("Student:执行构造方法");
    }
    {
        System.out.println("Student:执行实例代码块");
    }
    static{
        System.out.println("Student:执行静态代码块");
    }

    public static void main(String[] args) {
        Student a=new Student(20,"luka");
        System.out.println("------------------------");
        Student b=new Student(21,"stepth");
    }
}

/*
执行结果:
Person:执行静态代码块
Student:执行静态代码块
Person:执行实例代码块
Person:执行构造方法
Student:执行实例代码块
Student:执行构造方法
------------------------
Person:执行实例代码块
Person:执行构造方法
Student:执行实例代码块
Student:执行构造方法
*/

说明:
1、父类静态代码块优先于子类静态代码块执行,静态代码块相较于其他是最早执行。
2、父类实例代码块和父类构造方法紧接着执行。
3、子类的实例代码块和子类构造方法紧接着再执行。
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行(静态代码块只执行一次)。

8、父类成员在子类中的可见性

父类中不同访问权限的成员,在子类中的可见性又是什么样子的?

// extend01包中
public class B {
private int a;
protected int b;
public int c;
int d;
}
// extend01包中
// 同一个包中的子类
public class D extends B{
public void method(){
// super.a = 10; // 编译报错,父类private成员在相同包子类中不可见
super.b = 20; // 父类中protected成员在相同包子类中可以直接访问
super.c = 30; // 父类中public成员在相同包子类中可以直接访问
super.d = 40; // 父类中默认访问权限修饰的成员在相同包子类中可以直接访问
}
}
// extend02包中
// 不同包中的子类
public class C extends B {
public void method(){
// super.a = 10; // 编译报错,父类中private成员在不同包子类中不可见
super.b = 20; // 父类中protected修饰的成员在不同包子类中可以直接访问
super.c = 30; // 父类中public修饰的成员在不同包子类中可以直接访问
//super.d = 40; // 父类中默认访问权限修饰的成员在不同包子类中不能直接访问
}
}
// extend02包中
// 不同包中的类
public class TestC {
public static void main(String[] args) {
C c = new C();
c.method();
// System.out.println(c.a); // 编译报错,父类中private成员在不同包其他类中不可见
// System.out.println(c.b); // 父类中protected成员在不同包其他类中不能直接访问
System.out.println(c.c); // 父类中public成员在不同包其他类中可以直接访问
// System.out.println(c.d); // 父类中默认访问权限修饰的成员在不同包其他类中不能直接访问
}
}

**注意:**父类中private成员变量随时在子类中不能直接访问,但是也继承到子类中了。

9、继承方式

Java中支持以下几种继承方式:

单继承:

多层继承:

不同类继承同一个类

不支持多继承

10、final关键字

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

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

final int a = 10;
a = 20; // 编译出错

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

final public class Animal {
...
}
public class Bird extends Animal {
...
}
// 编译出错

平时使用的String字符串类,打开其源码可以看到它是被final修饰的,不可以被继承。

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

11、组合

组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果。组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字段。
这是继承和组合的区别。

//车闸类
class Brake{

}
//车把手类
class Handle{

}
//轮胎类
class Tire{

}

public class Bicycle {
    private Brake brake;    //可以复用车闸中的属性和方法
    private Handle handle;  //可以复用车把手中的属性和方法
    private Tire tire;      //可以复用轮胎中的属性和方法
}

作者:luka.lh
over!!!

到此这篇关于Java中的重要核心知识点之继承详解的文章就介绍到这了,更多相关Java 继承内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java面向对象关键字extends继承的深入讲解

    目录 一. 问题引出 二.继承extends 2.1 继承的用法 2.2 基本语法 2.3继承的好处 2.4继承性 总结 一. 问题引出 面向对象的编程思想使得代码中创建的类更加具体,他们都有各自的属性,方法.有的时候一些客观事物之前存在一些联系,那么他们在代码中的具体类也存在一些联系. 例如:设计一个动物类 public class Animal { public String name; public int age; public Animal(String name) { this.na

  • 一篇文章带你了解java接口与继承

    目录 JAVA接口的概念 接口的代码实现 定义关键字:interface 实现 关键字: implements 举个列子 注意事项 Java继承 什么是继承: 总结 JAVA接口的概念 官方解释:Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 我的理解:在类中,方法是具体的,通过接口我们可以将具体的方法抽象化.比如在动物类中有吃的动作,不同的动物吃不同的食物,食肉食草等

  • Java 基础语法之解析 Java 的包和继承

    目录 一.包 1. 概念 2. 使用方式 3. 静态导入 4. 创建包 5. 包的访问权限 6. 常见的系统包 二.继承 1. 概念 2. 语法规则(含 super 使用) 3. protected 关键字 4. 更复杂的继承关系 5. final 关键字 三.组合 四.总结(含谜底) 一.包 1. 概念 根据定义:包是组织类的一种方式 那么为什么要组织类呢? 简单来讲就是保证类的唯一性,就比如在以后的工作中,如果大家一起开发一个项目,大家可能在自己的代码中都写到了一个 Test 类,而如果出现

  • 一篇文章带你入门Java继承

    目录 Java中继承 什么是继承: 为什么要用继承: 学习总结: 继承关键字:extends 总结 Java中继承 什么是继承: 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为. 为什么要用继承: 可以去掉重复代码,方便后期维护 举个列子,大家应该都玩过英雄联盟,每个英雄都是一个类,如果说不用继承的话每次都要重复定义每个英雄的成员属性,如下图我举了一个MF,一个EZ的列子 public class MissFortu

  • Java语言之包和继承详解

    目录 一.包 包名 类的导入与静态导入 在包中添加类 包访问权限 二.继承 类.超类与子类 重写方法(override) this与super的区别: 子类构造器 protected关键字 阻止继承:final关键字 组合 总结 一.包 包名 在讲包名前,我们先来了解一下,包是用来干什么的? Java中允许使用包(package),包将类组织在一个集合中.借助包可以方便管理组织自己的代码,并将自己的代码与别人的提供的代码库分开管理. 包是组织类的一种方式.使用包的主要目的就是保证类的唯一性. 在

  • 一篇文章带你了解JAVA面对对象之继承与修饰符

    目录 Java面向对象之继承与修饰符 继承 1.含义 2.实现 3.好处 4.短处 5.成员变量的访问特点 7.继承中结构方法的访问特点 8.方法重写 9.java继承的注意事项 修饰符 1.package 2.import 3.权限修饰符 4.final 5.ianl修饰基本数据类型变量 6.final修饰引用数据类型变量 7.static 8.static访问的特点 总结 Java面向对象之继承与修饰符 继承 1.含义 继承是面向对象三大特征之一,能使子类具有父类的属性和方法,还可以在子类中

  • Java中的重要核心知识点之继承详解

    目录 一.继承 1.概念 2.语法 3.父类成员的访问 (1)子类中访问父类成员变量 (2)子类中访问父类成员方法 4.super关键字 5.子类构造方法 6.super和this 7.代码块执行顺序 8.父类成员在子类中的可见性 9.继承方式 10.final关键字 11.组合 一.继承 1.概念 继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类.继承呈现了面向对象程序设计的

  • Java中成员方法与成员变量访问权限详解

    记得在一次面试的笔试题中,有的面试官会要求写出具体的像pullic这些访问限定符的作用域.其实,平常我都没去系统的考虑这些访问限定符的作用域,特别是包内包外的情况,OK,笔试不行了. 这是java基本的知识,也是公司看重的,那没办法啦,我的脑袋记不住东西,那我只能把这些东西写下来方便自己温故知新,不废话了,贴代码了. 代码如下: package com.jaovo; /** *_1_ 成员变量访问权限的求证 * public private protected default(默认的权限) *自

  • java中压缩文件并下载的实例详解

    当我们对一些需要用到的资料进行整理时,会发现文件的内存占用很大,不过是下载或者存储,都不是很方便,这时候我们会想到把文件变成zip格式,即进行压缩.在正式开始压缩和下载文件之前,我们可以先对zip的格式进行一个了解,然后再就具体的方法给大家带来分享. 1.ZIP文件格式 [local file header + file data + data descriptor]{1,n} + central directory + end of central directory record 即 [文件

  • Java中Validated、Valid 、Validator区别详解

    目录 1. 结论先出 JSR 380 Valid VS Validated 不同点? Validator 2. @Valid和​​​​​​​@Validated 注解 3. 例子 4.使用@Valid嵌套校验 5. 组合使用@Valid和@Validated 进行集合校验 6. 自定义校验 自定义约束注解 工作原理 结论 参考链接: 1. 结论先出 Valid VS Validated 相同点 都可以对方法和参数进行校验 @Valid和@Validated 两种注释都会导致应用标准Bean验证.

  • Java中实现List分隔成子List详解

    目录 前言 一 ListUtils.partition 方法 二  Lists.partition 方法 三 源码分析 四 性能对比 总结 前言 在工作中经常遇到需要将数组分割成多个子数组,然后进行批量处理的需求.那有没有比较优雅的实现呢? 经过多次实践,总结出 ListUtils.partition 和 Lists.partition 两种较好实现 .下面对这两种实现分别进行说明. 一 ListUtils.partition 方法 1.1 引入依赖 <dependency> <grou

  • java中String StringBuffer和StringBuilder的区别详解

    目录 从声明定义上来谈 从结构上来谈 从线程安全来谈 总结 从声明定义上来谈 只有String 可以 直接声明创建 而 StringBuffer 与 StringBuilder 必须去new对象 这是因为只有String会在这种声明方式下去字符串常量池创建,其他则没有 StringBuffer stf = new StringBuffer("abc"); StringBuilder stb = new StringBuilder("abc"); StringBuff

  • Java 中 Class Path 和 Package的使用详解

    目录 一. 类路径 (class path) 二. 包 (package) 三. jar 文件 一. 类路径 (class path) 当你满怀着希望安装好了 java, 然后兴冲冲地写了个 hello world,然后编译,运行, 就等着那两个美好的单词出现在眼前, 可是不幸的是, 只看到了 Can't find class HelloWorld 或者 Exception in thread "main" java.lang.NoSuchMethodError : maain.为什么

  • Java中this和super关键字的使用详解

    目录 父类空间优先于子类对象产生 super和this的含义 super和this的用法 继承的特点 父类空间优先于子类对象产生 在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身.目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员.代码体现在子类的构造方法调用时,一定先调用父类的构造方法.理解图解如下: super和this的含义 super :代表父类的存储空间标识(可以理解为父亲的引用). this :代

  • java 中Excel转shape file的实例详解

    java  中Excel转shape file的实例详解 概述: 本文讲述如何结合geotools和POI实现Excel到shp的转换,再结合前文shp到geojson数据的转换,即可实现用户上传excel数据并在web端的展示功能. 截图: 原始Excel文件 运行耗时 运行结果 代码: package com.lzugis.geotools; import com.lzugis.CommonMethod; import com.vividsolutions.jts.geom.Coordina

  • 基于java中的PO VO DAO BO POJO(详解)

    一.PO:persistant object 持久对象,可以看成是与数据库中的表相映射的ava对象. 最简单的PO就是对应数据库中某个表中的一条记录,多个记录可以用PO的集合PO中应该不包含任何对数据库的操作. 二.VO:value object值对象.通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已.但应是抽象出的业务对象可以和表对应也可以不这根据业务的需要 三.DAO:data access object 数据访问对象,此对象用于访问数据库.通常和PO结合使用,DAO中包含了各种

随机推荐