初识java(十一):继承

目录

一:继承

1.为什么需要继承

2.继承概念

3.继承的语法

4.⽗类成员访问

1.⼦类中访问⽗类的成员变量

2.⼦类中访问⽗类的成员⽅法

5.super关键字

6.⼦类构造⽅法

7.super和this

8.继承关系上代码块等的初始化顺序

1.回顾之前的初始化顺序

2.继承关系上的执⾏顺序

9.访问修饰限定符-protected关键字

1.private关键字

2.不加任何的关键字

3.protected关键字

[4.public 关键字](#4.public 关键字)

10.继承⽅式

[1.final 关键字](#1.final 关键字)

11.继承与组合


内容大纲:

1.摘要:本文详细介绍了Java中的继承机制,通过猫狗动物案例展示了继承如何实现代码复用。

2.继承允许子类复用父类成员并扩展新功能,使用extends关键字建立继承关系。

3.重点讲解了super关键字的作用(访问父类成员、调用父类构造方法)、继承中的初始化顺序(父类静态→子类静态→父类实例→子类实例)以及访问修饰符protected的使用场景。

文章还对比了继承与组合的区别,指出继承表示"is-a"关系而组合表示"has-a"关系,建议优先使用组合。

4.最后介绍了final关键字限制继承的特性,并强调实际开发中应保持简洁的继承层次(不超过三层)。

一:继承

1.为什么需要继承

java中使⽤类对现实世界中实体来进⾏描述,类经过实例化之后的产物对象,则可以⽤来表⽰现实中的 实体,但是现实世界错综复杂,事物之间可能会存在⼀些关联,那在设计程序时就需要考虑

⽐如:狗和猫,它们都是**⼀个动物**

使⽤Java语⾔来进⾏描述,就会设计出这样的代码:

Dog.java

java 复制代码
public class Dog {
    String name;
    int age;
    float weight;

    public void eat(){
        System.out.println(name + " 正在吃饭 ");
    }
    public void sleep(){
        System.out.println(name + " 正在睡觉 ");
    }
    public void Bark(){
        System.out.println(name + " 汪汪汪 ~~~");
    }
}

Cat.java

java 复制代码
public class Cat {
    String name;
    int age;
    float weight;

    public void eat(){
        System.out.println(name + " 正在吃饭 ");
    }
    public void sleep(){
        System.out.println(name + " 正在睡觉 ");
    }
    public void Bark(){
        System.out.println(name + " 喵喵苗 ~~~");
    }

}

通过观察上述代码会发现,猫和狗的类中存在⼤量重复,如下所⽰:

那能否将这些共性抽取呢?⾯向对象思想中提出了继承的概念,专⻔⽤来进⾏共性抽取,实现代码复⽤

2.继承概念

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

例如:狗和猫都是动物 ,那么我们就可以将共性的内容进⾏抽 取,然后采⽤继承的思想来达到共⽤

上述图⽰中,Dog和Cat都继承了Animal类 ,其中:Animal类称为⽗类/基类或超类,Dog和Cat可以称 为Animal的⼦类/派⽣类,继承之后,⼦类可以复⽤⽗类中成员⼦类在实现时只需关⼼⾃⼰新增加的 成员即可。

从继承概念中可以看出继承最⼤的作⽤就是:实现代码复⽤,还有就是来实现多态(后序讲)

3.继承的语法

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

修饰符 class ⼦类 extends ⽗类 {

// ...

}

注意:
1.修饰符就是我们的public private ,,,,,这些修饰符

2.子类就是我们的猫猫狗狗

3.父类就是我们共有的特性即都是动物

对刚刚开始的猫狗代码中场景使⽤继承⽅式重新设计:

Dog.java(子类)

java 复制代码
public class Dog extends Animal{
    public void Bark(){
        System.out.println(name + " 汪汪汪 ~~~");
    }
}

Cat.java(子类)

java 复制代码
public class Cat extends Animal{
    public void Bark(){
        System.out.println(name + " 喵喵苗 ~~~");
    }
}

Animal.java(父类)

java 复制代码
public class Animal {
    String name;
    int age;
    float weight;

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

}

Test,java(测试上面的)

java 复制代码
public class Test {
    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类和Cat类的部分代码重复使⽤了Animal中的代码。

注意:

1.⼦类会将⽗类中的成员变量或者成员⽅法继承到⼦类中

2.⼦类继承⽗类之后,必须要新添加⾃⼰特有的成员,体现出与父类的不同,否则就没有必要继承了

4.⽗类成员访问

在继承体系中,⼦类将⽗类中的⽅法和字段(成员变量)继承下来了,那在⼦类中能否直接访问⽗类中继承下来的 成员呢?

1.⼦类中访问⽗类的成员变量

⼦类和⽗类不同名成员变量

Derived.java(子类)

java 复制代码
public class Derived extends Base {
    public static int c;

    public static void method(){
        a = 10;    //访问从⽗类中继承下来的a
        b = 20;    //访问从⽗类中继承下来的b
        c = 30;    //访问⼦类⾃⼰的c
    }
    public static void main(String[] args) {
        Derived.method();
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);

    }
}

Base.java(父类)

java 复制代码
public class Base {
   public static int a;
   public static int b;
}

输出:

⼦类和⽗类成员变量同名

Derived.java

java 复制代码
public class Derived extends Base {
    public static int a; //与⽗类中成员 a同名,且类型相同
    public static char b; //与⽗类中成员 b同名,但类型不同

    public static void method(){
        a = 100;  //访问⽗类继承的a,还是⼦类⾃⼰新增的a?
        b = 101;  //访问⽗类继承的 b,还是⼦类⾃⼰新增的 b?
        c = 102;  //⼦类没有c,访问的肯定是从⽗类继承下来的c
    }
    public static void main(String[] args) {
        Derived.method();
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);

    }
}

Base.java

java 复制代码
public class Base {
    public static int a;
    public static int b;
    public static int c;
}

输出:

注意:上面的e就是101的字符形式,因为我们是char类型

在 Derived 类重点 method ⽅法中访问a和b访问的都是优先访问⼦类⾃⼰的!

在⼦类⽅法中或者通过⼦类对象访问成员时:

• 如果访问的成员变量⼦类中有,优先访问⾃⼰的成员变量。

• 如果访问的成员变量⼦类中⽆,则访问⽗类继承下来的,如果⽗类也没有定义,则编译报错。

• 如果访问的成员变量与⽗类中成员变量同名,则优先访问⾃⼰的。

成员变量访问遵循就近原则,⾃⼰有优先⾃⼰的,如果没有则向⽗类中找。

2.⼦类中访问⽗类的成员⽅法

成员⽅法名字不同

Derived.java

java 复制代码
public class Derived extends Base {

    public static void methodB(){
        System.out.println("Derived 中的 methodB()⽅法 ");
    }
    public static void methodC(){
        methodB(); //访问⼦类⾃⼰的methodB()
        methodA(); //访问⽗类继承的methodA()
    }
    public static void main(String[] args) {
        Derived.methodC();
    }
}

Base.java

java 复制代码
public class Base {
    public static void methodA(){
        System.out.println("Base 中的 methodA()");
    }
}

输出:

总结:成员⽅法没有同名时,在⼦类⽅法中或者通过⼦类对象访问⽅法时,则优先访问⾃⼰的,⾃⼰ 没有时再到⽗类中找,如果⽗类中也没有则报错

成员⽅法名字相同

Derived.java

java 复制代码
public class Derived extends Base {

    public static void methodA() {
        System.out.println("Derived 中的 method()⽅法 ");
    }
    public static void methodB(){
        System.out.println("Derived 中的 methodB()⽅法 ");
    }
    public static void methodC(){
        methodA(); //优先访问⼦类中的methodA()
        methodB(); //直接访问,则永远访问到的都是⼦类中的methodB(),父类无法访问

    }
    public static void main(String[] args) {
        Derived.methodC();
    }
}

Base.java

java 复制代码
public class Base {
    public static void methodA(){
        System.out.println("Base 中的 methodA()");
    }
    public static void methodB(){
        System.out.println("Base 中的 methodB()");
    }
}

输出

【说明】

通过⼦类对象访问⽗类与⼦类中**不同名⽅法时,优先在⼦类中找,**找到则访问,否则在⽗类中找, 找到则访问,否则编译报错。

通过子类对象访问⽗类与⼦类同名⽅法时,如果⽗类和⼦类同名⽅法的参数列表不同(重载),根据调⽤⽅法适传递的参数选择合适的⽅法访问,如果没有则报错

问题:如果⼦类中存在与⽗类中相同的成员时,那如何在⼦类中访问⽗类相同名称的成员呢?

5.super关键字

由于设计不好,或者因场景需要,⼦类和⽗类中可能会存在相同名称的成员,如果要在⼦类⽅法中访 问⽗类同名成员时,该如何操作?直接访问是⽆法做到的,Java提供了super关键字,该关键字主要 作⽤:在⼦类⽅法中访问⽗类的成员。

Derived.java

java 复制代码
public class Derived extends Base {
    public static int a; // 子类自己的静态变量 a(隐藏了父类的 a)
    public static int b; // 子类自己的静态变量 b(隐藏了父类的 b)

    public static void methodA(int a) {
        System.out.println("Derived 中的 methodA(int a) 方法,接收到的参数是:" + a);
    }

    public static void methodB() {
        System.out.println("Derived 中的 methodB() 方法");
    }

    public void methodC() {
        // 1. 通过 super 给父类的静态变量赋值
        super.a = 200; 
        super.b = 201; 

        // 2. 【核心修改】加上 super 的对比打印,直观体现 super 的作用
        System.out.println("直接访问子类的 a: " + a);
        System.out.println("通过super访问父类的 a: " + super.a); 
        System.out.println("直接访问子类的 b: " + b);
        System.out.println("通过super访问父类的 b: " + super.b); 

        // 3. 原有的方法调用
        methodA();      // 没有传参,访问父类中的 methodA()
        methodA(20);    // 传递了参数,访问子类中的 methodA(int)
        methodB();      // 直接访问,永远访问到的都是子类中的 methodB()
        super.methodB(); // 借助 super,明确访问基类的 methodB()
    }

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

Base.java

java 复制代码
public class Base {
    public static int a; // 父类的静态变量 a
    public static int b;

    public static void methodA() {
        System.out.println("Base 中的 methodA()");
    }

    public static void methodB() {
        System.out.println("Base 中的 methodB()");
    }
}

输出:

直接访问子类的 a: 0

通过super访问父类的 a: 200

直接访问子类的 b: 0

通过super访问父类的 b: 201

Base 中的 methodA()

Derived 中的 methodA(int a) 方法,接收到的参数是:20

Derived 中的 methodB() 方法

Base 中的 methodB()

在⼦类⽅法中,如果想要明确访问⽗类中成员时,借助super关键字即可。

注意事项

只能在⾮静态⽅法中使⽤

只能在⼦类⽅法中,访问⽗类的成员变量和⽅法

总结:

结合我们刚刚的实战代码,super 关键字的作用其实非常直观。你可以把它简单地理解为**"子类手里的一把专属钥匙"**,专门用来在子类中打开和访问父类的成员。

在 Java 继承中,super 主要有以下三大核心用途:

1. 访问父类被隐藏的成员变量 (super.变量名)

当子类和父类定义了同名的变量时,直接写变量名默认访问的是子类自己的(就近原则)。此时如果想访问父类的变量,就必须用 super

2. 调用父类被重写的方法 (super.方法名())

当子类重写(Override)了父类的方法时,直接调用会默认执行子类的版本。如果想在子类里复用父类原本的逻辑,就必须用 super

3. 调用父类的构造方法 (super()super(参数))

在创建子类对象时,必须先初始化父类部分。super() 专门用于在子类构造方法的第一行,调用父类的构造器。

一句话总结:

super 就是为了解决"子类想用自己的东西,但又偶尔需要用到父类原版"的需求而存在的。只要加上 super.,Java 就会直接跳过子类,去父类里找对应的变量、方法或构造器!

6.⼦类构造⽅法

我们先来看⼀段代码:

Derived.java

java 复制代码
public class Derived extends Base {
public Derived(){
    System.out.println("Derived()");
}
}

Base.java

java 复制代码
public class Base {
    public Base(int a) {
        System.out.println("Base(): " + a);
    }
}

Test.java

java 复制代码
public class Test {
    public static void main(String[] args) {
        Derived d = new Derived();
    }
}

输出:

问题:该代码为什么会编译错误呢?

事实上,当我们在构造⼦类对象的时候,需要先调⽤父类构造⽅法,然后执⾏⼦类的构造⽅法。所 以,我们需要在⼦类对象构造完成之前先帮助⽗类对其中的成员进⾏初始化。具体⽅式如下:

我们只需更改:
Derived.java

java 复制代码
public class Base {
    public Base(int a) {
        super(10);//此时通过super(参数)的形式
        System.out.println("Base(): " + a);
    }
}

输出:

【注意事项】

通过super(参数)的形式可以调⽤⽗类指定的构造⽅法

super()的形式只能出现在⼦类的构造⽅法当中且必须在第⼀⾏

问题:如下代码为什么没有报错呢?

Derived.java

java 复制代码
public class Derived extends Base {
public Derived(){
    System.out.println("Derived()");
}
}

Base.java

java 复制代码
public class Base {
    public Base() {
        System.out.println("Base()");
    }
}

输出:

【注意事项】:

正如注释处所说,当**⽗类的构造⽅法是不带参数的构造⽅法且只有这⼀个的情况下,默认会添加⼀ 个super()。**

【总结】

• 在⼦类构造⽅法中,并没有写任何关于父类构造的代码,但是在构造⼦类对象时,先执⾏父类的构 造⽅法,然后执⾏⼦类的构造⽅法,因为:⼦类对象中成员是有两部分组成的,父类继承下来的以 及⼦类新增加的部分。⽗⼦肯定是先有⽗再有⼦,所以在构造⼦类对象时候,先要调⽤父类 的构造⽅法,将从父类继承下来的成员构造完整,然后再调⽤⼦类⾃⼰的构造⽅法,将⼦类⾃⼰新 增加的成员初始化完整。

• 若⽗类显式定义⽆参或者默认的构造⽅法,在⼦类构造⽅法第⼀⾏默认有隐含的super()调⽤,即调⽤父类构造⽅法

• 如果⽗类构造⽅法是带有参数的,此时需要⽤⼾为⼦类显式定义构造⽅法,并在⼦类构造⽅法中选择合适的⽗类构造⽅法调⽤,否则编译失败

• 在⼦类构造⽅法中,super(...)调⽤⽗类构造时,必须是⼦类构造函数中第⼀条语句

• super(...)只能在⼦类构造⽅法中出现⼀次,并且不能和this同时出现

7.super和this

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

【相同点】

  1. 都是Java中的关键字

  2. 只能在类的⾮静态⽅法中使⽤,⽤来访问⾮静态成员⽅法和字段

  3. 在构造⽅法中调⽤时,必须是构造⽅法中的第⼀条语句,并且不能同时存在

【不同点】

  1. this是当前对象的引⽤,当前对象即调⽤实例⽅法的对象,super相当于是⼦类对象中从⽗类继承下 来部分成员的引⽤
  1. 在⾮静态成员⽅法中,this⽤来访问本类的⽅法和属性,super⽤来访问⽗类继承下来的⽅法和属性

  2. 在构造⽅法中:this(...)⽤于调⽤本类构造⽅法,super(...)⽤于调⽤⽗类构造⽅法,两种调⽤不能同时在构造⽅法中出现

  3. 构造⽅法中⼀定会存在super(...)的调⽤,⽤⼾没有写编译器也会增加,但是this(...)⽤⼾不写则没有

8.继承关系上代码块等的初始化顺序

1.回顾之前的初始化顺序

我们还记得之前讲过的代码块吗?我们简单回顾⼀下⼏个重要的代码块:实例代码块和静态代码块。 在没有继承关系时的执⾏顺序

Test.java

java 复制代码
public class Test {
    public static void main(String[] args) {
        Person person1 = new Person("bit",10);
        System.out.println("============================");
        Person person2 = new Person("小龙",20);
    }
}

Person.java

java 复制代码
public 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(" 静态代码块执⾏");
    }


}

输出:

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

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

2.继承关系上的执⾏顺序

Student.java(子类)

java 复制代码
public 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:静态代码块执⾏ ");
        }
}

Person.java(父类)

java 复制代码
public 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 静态代码块执⾏");
    }
    
}

输出:

通过分析执⾏结果,得出以下结论:

1. ⽗类静态代码块优先于⼦类静态代码块执⾏,且是最早执⾏

2. ⽗类实例代码块和⽗类构造⽅法紧接着执⾏

3. ⼦类的实例代码块和⼦类构造⽅法紧接着再执⾏

4. 第⼆次实例化⼦类对象时,⽗类和⼦类的静态代码块都将不会再执⾏

9.访问修饰限定符-protected关键字

在类和对象章节中,为了实现封装特性,Java中引⼊了访问限定符,主要限定:类或者类中成员能否 在类外或者其他包中被访问。

那⽗类中不同访问权限的成员,在⼦类中的可⻅性⼜是什么样⼦的呢?

1.private关键字

如果被 private 关键字修饰该类当中成员变量,成员⽅法等只能在当前类当中使⽤

2.不加任何的关键字(包访问权限)

如果不加任何的关键字修饰该类当中成员变量,成员⽅法等表⽰默认权限,默认权限代表的也是包访问权限,意味着只能在当前包当中使⽤

3.protected关键字

如果被 protected 关键字修饰该类当中成员变量,成员⽅法等表⽰要么只能在同⼀个包中的类中进 ⾏访问,要么在不同包中只能通过在继承关系上的⼦类对象来访问

4.public 关键字

如果被 public 关键字修饰该类当中成员变量,成员⽅法等表⽰该成员变量和成员⽅法是公开的

什么时候下⽤哪⼀种呢?

1.我们希望类要尽量做到"封装",即隐藏内部实现细节,只暴露出必要的信息给类的调⽤者.

2.因此我们在使⽤的时候应该尽可能的使⽤⽐较严格的访问权限.例如如果⼀个⽅法能⽤private,就尽量不要⽤public.

3.另外,还有⼀种简单粗暴的做法:将所有的字段设为private,将所有的⽅法设为public.不过这种⽅ 式属于是对访问权限的滥⽤,还是更希望同学们能写代码的时候认真思考,该类提供的字段⽅法到底 给"谁"使⽤(是类内部⾃⼰⽤,还是类的调⽤者使⽤,还是⼦类使⽤).

10.继承⽅式

在Java中只⽀持以下⼏种继承⽅式:

注意:Java中不⽀持多继承

1.时刻牢记,我们写的类是现实事物的抽象.⽽我们真正在公司中所遇到的项⽬往往业务⽐较复杂,可能 会涉及到⼀系列复杂的概念,都需要我们使⽤代码来表⽰,所以我们真实项⽬中所写的类也会有很多. 类之间的关系也会更加复杂

2.但是即使如此,我们并不希望类之间的继承层次太复杂.⼀般我们不希望出现超过三层的继承关系.如 果继承层次太多,就需要考虑对代码进⾏重构了.

3.如果想从语法上进⾏限制继承,就可以使⽤final关键字

1.final 关键字

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

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

final int a = 10;

a = 20;

// 编译出错

修饰类:表⽰此类不能被继承

//父类

final public class Animal {

...

}

//子类

public class Bird extends Animal {

...

}

我们平时是⽤的String字符串类,就是⽤final修饰的,不能被继承

修饰⽅法:表⽰该⽅法不能被重写(后序介绍)

11.继承与组合

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

继承表⽰对象之间是is-a的关系,⽐如:狗是动物,猫是动物

组合表⽰对象之间是has-a的关系,⽐如:汽⻋

汽⻋和其轮胎、发动机、⽅向盘、⻋载系统等的关系就应该是组合,因为汽⻋是有这些部件组成的。

//轮胎类

class Tire{

...

}

// 发动机类

class Engine{

...

}

// ⻋载系统类

class VehicleSystem{

...

}

//汽车

class Car{

private Tire tire; // 可以复⽤轮胎中的属性和⽅法

private Engine engine; // 可以复⽤发动机中的属性和⽅法

private VehicleSystem vs; // 可以复⽤⻋载系统中的属性和⽅法

...

}

class Benz extend Car{

// 将汽⻋中包含的:轮胎、发送机、⻋载系统全部继承下来

}

组合和继承都可以实现代码复⽤,应该使⽤继承还是组合,需要根据应⽤场景来选择,⼀般建议:能 ⽤组合尽量⽤组合。

以上就是我们的全部内容了!!!!!!(大大的重点)

相关推荐
CoderYanger6 小时前
A.每日一题:3612. 用特殊操作处理字符串 I
java·程序人生·leetcode·面试·职场和发展·学习方法·改行学it
江华森6 小时前
高级 Bash 脚本编程指南 — 实战教程
开发语言·bash
我不是懒洋洋6 小时前
【C++】string(string的成员变量、auto和范围for、string常用接口的说明、OJ题目、string的模拟实现)
c语言·开发语言·c++·visual studio
Brilliantwxx7 小时前
【C++】 C++11 知识点梳理(中)
开发语言·c++
j7~7 小时前
【C++】STL--Vector容器--拆析解剖Vector的实现以及Vector的底层详解(2)
开发语言·c++·动态二维数组·vector深度剖析·vector的实现·杨辉三角形
唐青枫8 小时前
Java Flyway 实战指南:用 SQL 脚本管理数据库版本
java
三品吉他手会点灯14 小时前
C语言学习笔记 - 50.流程控制4 - 流程控制为什么非常非常重要
c语言·开发语言·笔记·学习
huangdong_15 小时前
电商平台图片URL原图转换技术深度解析:从缩略图到高清原图的完整方案
java·后端·spring
記億揺晃着的那天15 小时前
Java 调用外部 Go 程序的实践:ProcessBuilder 在生产环境中的应用
java·golang·processbuilder
JAVA面经实录91715 小时前
Java 数据结构与算法 (终极完整学习文档)
java·数据结构·算法