java之面向对象

1 类与对象

1.1面向对象概念

1.1.1 面向过程

在一个结构体中定义窗口的大小,位置,颜色,背景等属性,对窗口操作的函数与窗口本身的定义没有任何关系,如HideWindow,MoveWindow,MinimizeWindow,这些函数都需要接受一个代表要被操作的窗口参数,是一种谓语与宾语的关系。中心在实现问题或完成的功能的具体过程中

1.1.2 面向对象

定义窗口时,除了要指定在面向过程中规定的那些属性,如大小,位置,颜色,背景等外,还要指定该窗口可能具有的动作,如隐藏,移动,最小化等。这些函数被调用时,都是以某个窗口要隐藏,某个窗口要移动的语法格式来使用的,这是一种主语与谓语的关系。重在对象,只需要知道什么对象有什么方法使用即调用即可

1.1.3 面向对象的三大特征

封装(Encapsulation) 继承(Inheritance) 多态(Polymorphism)

1.2 面向对象

  • 面向对象的编程思想力图使计算机语言中对事物的描述与现实世界中该事物的本来面目尽可能的一致。

  • 类(class)和对象(object)是面向对象方法的核心概念。类是对一类事物描述,是抽象的、概念上的定义;对象是实际存在的该类事物的每个个体,因而也称实例(instance)

  • 类是一个模板,对象是模板的具体实例

1.3 类的定义

两部分组成:属性、方法

1.3.1 声明属性:

语法格式: [<修饰符>]类型<属性名>[=初值]; 说明:修饰符private:该属性只能由该类的方法访问。 修饰符public:该属性可以被该类以外的方法访问。 类型:任何基本类型,如int、boolean或任何类。

<span style="background-color:#f8f8f8"><span style="color:#333333">public class Person{
private int age;    //声明private变量age
public String name ="llila"; //声明public变量name
}</span></span>

属性有时也称为:数据成员(数据),成员变量(变量)

1.3.2 声明方法

语法格式:

<修饰符><返回类型><方法名>([<参数表>)){ [<语句>] } 说明:修饰符:public,private,protected等。 返回类型:return语句传递返回值。没有返回值:void。

<span style="background-color:#f8f8f8"><span style="color:#333333">public class Person{
private int age;
        public int getAge(){ return age;} //声明方法getAge
        public void setAge(int i){      //声明方法setAge
        age =i; //将参数i的值赋给类的成员变量ago
}
}</span></span>

1.3.3 声明类

语法格式: [ <修饰符>]class<类名> { [<属性声明>] [<构造器声明] [<方法声明>] }

说明:修饰符public:类可以被任意访问 类的正文要用{ }括起来 注意:类名必须要与文件名完全一致,一个文件中可以存在多个类,但是只能用一个类被public所修饰

<span style="background-color:#f8f8f8"><span style="color:#333333">public class Animal
{
    public int legs;
    public void eat(){
        System.out.println("Eating.");
    }
    public void move(){
        System.out.println("Moving.");
    }
}</span></span>

legs是类的属性,也可以类成员变量。

eat,move是方法也叫类的成员函数。

<span style="background-color:#f8f8f8"><span style="color:#333333">public class Person{
    private int age;   //声明私有变量age
    public void showAge(int i){ //声明方法showAge
    age =i;
    }
}</span></span>

1.4 对象的创建与使用

对象的创建是通过 new 关键字和类的构造方法实现的。对象创建后,可以使用 . 运算符来访问对象的属性和方法。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {  
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {  
        <span style="color:#aa5500">// 对象的创建  </span>
        <span style="color:#000000">MyClass</span> <span style="color:#000000">myObject</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">MyClass</span>();  
  
        <span style="color:#aa5500">// 使用对象的属性  </span>
        <span style="color:#000000">myObject</span>.<span style="color:#000000">myInt</span> <span style="color:#981a1a">=</span> <span style="color:#116644">10</span>;  
        <span style="color:#000000">myObject</span>.<span style="color:#000000">myString</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"Hello"</span>;  
  
        <span style="color:#aa5500">// 使用对象的方法  </span>
        <span style="color:#000000">myObject</span>.<span style="color:#000000">myMethod</span>();  
    }  
}</span></span>

如果创建了一个类的多个对象,对于类中定义的属性,每个对象都拥有各自的一套副本,且互不干扰

<span style="background-color:#f8f8f8"><span style="color:#333333">public class Zoo{
    public static void main(String args[]){
    Animal xb=new Animal():
    Animal xh=new Animal():
    xb.legs=4;
    xh.legs=0;
    System.out.println(xb.legs); //4
    System.out.println(xh.legs); //0
    xb.legs=2;
    System.out.println(xb.legs); //2
    System.out.println(xh.legs); //0
    }
}</span></span>

类的访问机制: 在一个类中的访问机制:类中的方法可以直接访问类中的成员变量。(有一个例外) 在不同类中的访问机制:先创建要访问类的对象,再用对象访问类中定义的成员。 总结:类中的属性和方法虽然是公共的,但是具体出来的对象的属性和方法都是独立的(对象的数据相互隔离)

1.5 对象的产生

对象的产生是通过 new 关键字来调用类的构造方法完成的。这个过程包括在内存中为对象分配空间,并初始化对象的属性。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">MyClass</span> <span style="color:#000000">myObject</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">MyClass</span>(); <span style="color:#aa5500">// 对象产生</span></span></span>

1.6 对象的使用

对象的使用包括访问对象的属性和调用对象的方法。使用 . 运算符可以访问对象的成员。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">// 访问对象的属性  </span>
<span style="color:#008855">int</span> <span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#000000">myObject</span>.<span style="color:#000000">myInt</span>;  
<span style="color:#008855">String</span> <span style="color:#000000">text</span> <span style="color:#981a1a">=</span> <span style="color:#000000">myObject</span>.<span style="color:#000000">myString</span>;  
  
<span style="color:#aa5500">// 调用对象的方法  </span>
<span style="color:#000000">myObject</span>.<span style="color:#000000">myMethod</span>();</span></span>

1.7 对象的生命周期

对象的生命周期是指对象从创建到销毁的过程。这包括对象的初始化、对象的使用和对象的垃圾回收。

  • 初始化:通过 new 关键字创建对象,并在堆内存中分配空间。

  • 使用:通过引用变量访问和操作对象。

  • 垃圾回收:当对象不再被引用时,Java 的垃圾回收器会自动回收对象占用的内存。

1.8 匿名对象

匿名对象是指没有引用变量指向的对象。它通常用于只需要使用对象一次的场景,如调用一个方法后立即丢弃对象。

new MyClass().myMethod(); // 匿名对象的使用

在这个例子中,new MyClass() 创建了一个 MyClass 的匿名对象,并立即调用了它的 myMethod 方法。之后,由于没有引用变量指向这个对象,它将被垃圾回收器回收。

1.9 案例代码

下面是一个简单的案例代码,展示了类的定义、对象的创建与使用,以及匿名对象的使用。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Car</span> {  
    <span style="color:#008855">String</span> <span style="color:#000000">color</span>;  
    <span style="color:#008855">int</span> <span style="color:#000000">speed</span>;  
  
    <span style="color:#770088">public</span> <span style="color:#000000">Car</span>(<span style="color:#008855">String</span> <span style="color:#000000">color</span>) {  
        <span style="color:#770088">this</span>.<span style="color:#000000">color</span> <span style="color:#981a1a">=</span> <span style="color:#000000">color</span>;  
        <span style="color:#770088">this</span>.<span style="color:#000000">speed</span> <span style="color:#981a1a">=</span> <span style="color:#116644">0</span>;  
    }  
  
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">accelerate</span>(<span style="color:#008855">int</span> <span style="color:#000000">increment</span>) {  
        <span style="color:#000000">speed</span> <span style="color:#981a1a">+=</span> <span style="color:#000000">increment</span>;  
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Car is now going "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">speed</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">" km/h"</span>);  
    }  
}  
  
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {  
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {  
        <span style="color:#aa5500">// 创建对象  </span>
        <span style="color:#000000">Car</span> <span style="color:#000000">myCar</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Car</span>(<span style="color:#aa1111">"Red"</span>);  
  
        <span style="color:#aa5500">// 使用对象  </span>
        <span style="color:#000000">myCar</span>.<span style="color:#000000">accelerate</span>(<span style="color:#116644">10</span>); <span style="color:#aa5500">// Car is now going 10 km/h  </span>
  
        <span style="color:#aa5500">// 匿名对象  </span>
        <span style="color:#770088">new</span> <span style="color:#000000">Car</span>(<span style="color:#aa1111">"Blue"</span>).<span style="color:#000000">accelerate</span>(<span style="color:#116644">20</span>); <span style="color:#aa5500">// Car is now going 20 km/h  </span>
    }  
}</span></span>

2 信息封装与隐藏

2.1 信息封装

信息封装是将对象的属性(数据成员)和行为(方法)包装在一个类中,以保护对象的内部状态。信息封装可以通过访问控制修饰符(如 publicprivateprotected 和默认访问权限)来实现。

2.2 访问控制修饰符

  • public:公共访问权限,表示类、属性和方法可以被任何其他类访问。

  • private:私有访问权限,表示类、属性和方法只能被声明它们的类访问。

  • protected:受保护的访问权限,表示类、属性和方法可以被同一个包中的类以及子类访问。

  • 默认访问权限(无修饰符):表示类、属性和方法可以被同一个包中的类访问。

2.3 信息隐藏

信息隐藏是通过将类的实现细节隐藏起来,只暴露必要的接口,以保护对象的内部状态。信息隐藏可以通过将属性设置为私有(private)并提供公共(public)的 getter 和 setter 方法来实现。

2.4 案例

下面是一个简单的 Java 类定义示例,演示了如何使用 private 关键字实现信息封装和隐藏。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">// 定义一个类:Person</span>
<span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#aa5500">// 使用 private 关键字封装属性</span>
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
    <span style="color:#770088">private</span> <span style="color:#008855">int</span> <span style="color:#000000">age</span>;
​
    <span style="color:#aa5500">// 构造方法</span>
    <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>, <span style="color:#008855">int</span> <span style="color:#000000">age</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>;
    }
​
    <span style="color:#aa5500">// 提供公共的 getter 和 setter 方法</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getName</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setName</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">getAge</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">age</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setAge</span>(<span style="color:#008855">int</span> <span style="color:#000000">age</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>;
    }
​
    <span style="color:#008855">void</span> <span style="color:#000000">introduce</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"My name is "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">" and I am "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">age</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">" years old."</span>);
    }
}
​
<span style="color:#aa5500">// 主类,包含 main 方法</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">// 创建一个 Person 对象</span>
        <span style="color:#000000">Person</span> <span style="color:#000000">person1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>, <span style="color:#116644">30</span>);
​
        <span style="color:#aa5500">// 通过 getter 和 setter 方法访问对象的属性</span>
        <span style="color:#000000">person1</span>.<span style="color:#000000">setName</span>(<span style="color:#aa1111">"Bob"</span>);
        <span style="color:#000000">person1</span>.<span style="color:#000000">setAge</span>(<span style="color:#116644">25</span>);
​
        <span style="color:#aa5500">// 调用对象的方法</span>
        <span style="color:#000000">person1</span>.<span style="color:#000000">introduce</span>();
    }
}</span></span>

3 构造方法(构造器)

3.1构造器的定义、作用

需要注意的是:当new的时候其实就是调用了需要创建对象的类的构造器 1.构造方法的特征 它具有与类相同的名称; 它不含返回值; 注意:在构造方法里不含返回值的概念是不同于“void”的,在定义构造方法时加了“void”,结果这个方法就不再被自动调了 2.构造方法的作用l 当一个类的实例对象刚产生时,这个类的构造方法就会被自动调用,我们可以在这个方法中加入要完成初始化工作的代码。这就好像我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造方法中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。 注意: (1)如果手动创建一个含参构造器,就必须手动的创建一个无参构造器,不然的话就会出现编译错误 (2)默认不创建构造器,系统在编译类的时候也会自动创建一个无参构造器

3.2 表现形式

功能:创建类的实例时,初始化实例的一组指令.语法格式: <修饰符><类名>([<参数表>){

[<语句>] }

<span style="background-color:#f8f8f8"><span style="color:#333333">class ClassName {
    // 属性(数据成员)
    dataType attribute1;
    dataType attribute2;
​
    // 构造方法
    ClassName(dataType attribute1, dataType attribute2) {
        this.attribute1 = attribute1;
        this.attribute2 = attribute2;
    }
}</span></span>

注释:构造器的名称必须与类名相同。修饰符:public、private、protected构造器不是一般的方法,没有返回值(连void也不能写)

3.3 默认构造方法

  • Java语言中,每个类都至少有一个构造方法;

  • 如果类的定义者没有显式的定义任何构造方法,系统将自动提供一个默认的构造方法:

(1)默认构造方法没有参数 (2)默认构造方法没有方法体 (3)默认的构造方法: Animal(){}

所以:不编写构造方法就能用new Xxx()创建类的实例。

  • Java类中,一旦类的定义者显式定义了一个或多个构造方法,系统将不再提供默认的构造方法;

  • 构造器的主要作用:利用构造器参数初始化对象的属性。

4 方法的重载

1、发生在同一类中2、方法名完全相同3、和返回类型没有关系4、参数列表不相同(参数的个数、类型、顺序)

4.1 方法的定义

<span style="background-color:#f8f8f8"><span style="color:#333333">返回值类型 方法名([形参列表])[throws 异常列表]{
方法体的功能代码
}</span></span>

(1)一个完整的方法 = 方法头 + 方法体。 方法头就是 [修饰符] 返回值类型 方法名([形参列表])[throws 异常列表] ,也称为 方法签名 。通 常调用方法时只需要关注方法头就可以,从方法头可以看出这个方法的功能和调用格式。 方法体就是方法被调用后要执行的代码。对于调用者来说,不了解方法体如何实现的,并不影响方 法的使用。 (2)方法头可能包含5个部分 修饰符:可选的。方法的修饰符也有很多,例如:public、protected、private、static、abstract、native、final、synchronized等。

  • 其中,权限修饰符有public、protected、private。在讲封装性之前,我们先默认使用pulbic修饰方法。

  • 其中,根据是否有static,可以将方法分为静态方法和非静态方法。其中静态方法又称为类方法,非静态方法又称为实例方法。咱们在讲static前先学习实例方法。

返回值类型: 表示方法运行的结果的数据类型,方法执行后将结果返回到调用者。

  • 无返回值,则声明:void

  • 有返回值,则声明出返回值类型(可以是任意类型)。与方法体中“ return 返回值 ”搭配使用

方法名:属于标识符,命名时遵循标识符命名规则和规范,“见名知意” 形参列表:表示完成方法体功能时需要外部提供的数据列表。可以包含零个,一个或多个参数。

  • 无论是否有参数,()不能省略

  • 如果有参数,每一个参数都要指定数据类型和参数名,多个参数之间使用逗号分隔,例如:

    一个参数: (数据类型 参数名)

    二个参数: (数据类型1 参数1, 数据类型2 参数2)

  • 参数的类型可以是基本数据类型、引用数据类型

throws 异常列表:可选,在【第09章-异常处理】章节再讲 (3)方法体:方法体必须有{}括起来,在{}中编写完成方法功能的代码 (4)关于方法体中return语句的说明:

  • return语句的作用是结束方法的执行,并将方法的结果返回去

  • 如果返回值类型不是void,方法体中必须保证一定有 return 返回值; 语句,并且要求该返回值结果的 类型与声明的返回值类型一致或兼容。

  • 如果返回值类型为void时,方法体中可以没有return语句,如果要用return语句提前结束方法的执 行,那么return后面不能跟返回值,直接写return ; 就可以。

  • return语句后面就不能再写其他代码了,否则会报错:Unreachable code

案例

<span style="background-color:#f8f8f8"><span style="color:#333333">​
/**
* 方法定义案例演示
*/
public class MethodDefineDemo {
/**
* 无参无返回值方法的演示
*/
public void sayHello(){
System.out.println("hello");
}
/**
* 有参无返回值方法的演示
* @param length int 第一个参数,表示矩形的长
* @param width int 第二个参数,表示矩形的宽
* @param sign char 第三个参数,表示填充矩形图形的符号
*/
public void printRectangle(int length, int width, char sign){
for (int i = 1; i <= length ; i++) {
for(int j=1; j <= width; j++){
System.out.print(sign);
}
System.out.println();
}
}
/**
* 无参有返回值方法的演示
* @return
*/
public int getIntBetweenOneToHundred(){
return (int)(Math.random()*100+1);
}
/**
* 有参有返回值方法的演示
* @param a int 第一个参数,要比较大小的整数之一
* @param b int 第二个参数,要比较大小的整数之二
* @return int 比较大小的两个整数中较大者的值
*/
public int max(int a, int b){
return a > b ? a : b;
}
}</span></span>

4.2 方法的调用

方法通过方法名被调用,且只有被调用才会执行。

4.2.1 方法调用语法格式

<span style="background-color:#f8f8f8"><span style="color:#333333">对象.方法名([实参列表])</span></span>

4.2.2 案例

<span style="background-color:#f8f8f8"><span style="color:#333333">/**
* 方法调用案例演示
*/
public class MethodInvokeDemo {
    public static void main(String[] args) {
        //创建对象
        MethodDefineDemo md = new MethodDefineDemo();
        System.out.println("-----------------------方法调用演示-------------------------");
        //调用MethodDefineDemo类中无参无返回值的方法sayHello
        md.sayHello();
        md.sayHello();
        md.sayHello();
        //调用一次,执行一次,不调用不执行
        
        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中有参无返回值的方法printRectangle
        md.printRectangle(5,10,'@');
        
        System.out.println("------------------------------------------------");
        //调用MethodDefineDemo类中无参有返回值的方法getIntBetweenOneToHundred
            md.getIntBetweenOneToHundred();//语法没问题,就是结果丢失
            
            int num = md.getIntBetweenOneToHundred();
            System.out.println("num = " + num);
            
            System.out.println(md.getIntBetweenOneToHundred());
            //上面的代码调用了getIntBetweenOneToHundred三次,这个方法执行了三次
            
            System.out.println("------------------------------------------------");
            //调用MethodDefineDemo类中有参有返回值的方法max
            md.max(3,6);//语法没问题,就是结果丢失
            
            int bigger = md.max(5,6);
            System.out.println("bigger = " + bigger);
            System.out.println("8,3中较大者是:" + md.max(8,9));
        }
}</span></span>

4.2.3 使用注意点

(1)必须先声明后使用,且方法必须定义在类的内部

(2)调用一次就执行一次,不调用不执行。

(3)方法中可以调用类中的方法或属性,不可以在方法内部定义方法。

正确示例:

<span style="background-color:#f8f8f8"><span style="color:#333333">类{
方法1(){
}
方法2(){
}
}</span></span>

错误示例:

<span style="background-color:#f8f8f8"><span style="color:#333333">类{
方法1(){
方法2(){ //位置错误
}
}
}</span></span>

4.3 方法的重载

4.3.1 概念及特点

方法重载:在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可。

参数列表不同,意味着参数个数或参数类型的不同

重载的特点:与修饰符、返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参

数类型)。调用时,根据方法参数列表的不同来区别。

重载方法调用:JVM通过方法的参数列表,调用匹配的方法。

先找个数、类型最匹配的

再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错

4.3.2 案例

例1:

<span style="background-color:#f8f8f8"><span style="color:#333333">//System.out.println()方法就是典型的重载方法,其内部的声明形式如下:
public class PrintStream {
    public void println(byte x)
    public void println(short x)
    public void println(int x)
    public void println(long x)
    public void println(float x)
    public void println(double x)
    public void println(char x)
    public void println(double x)
    public void println()
}
public class HelloWorld{
    public static void main(String[] args) {
    System.out.println(3);
    System.out.println(1.2f);
    System.out.println("hello!");
}
}</span></span>

例2:

<span style="background-color:#f8f8f8"><span style="color:#333333">//返回两个整数的和
public int add(int x,int y){
    return x+y;
}
//返回三个整数的和
public int add(int x,int y,int z){
    return x+y+z;
}
//返回两个小数的和
public double add(double x,double y){
    return x+y;
}</span></span>

例3:方法的重载和返回值类型无关

<span style="background-color:#f8f8f8"><span style="color:#333333">public class MathTools {
//以下方法不是重载,会报错
public int getOneToHundred(){
    return (int)(Math.random()*100);
}
public double getOneToHundred(){
        return Math.random()*100;
    }
}</span></span>

5 关键字:this

5.1 this的定义

在Java中,this是一个特殊的关键字,它引用当前对象的一个实例。this关键字用于以下场景:

  1. 引用当前对象的属性:当方法的参数名与类的成员变量名相同时,可以使用this来区分它们。

  2. 引用当前对象的其他方法:当方法内部需要调用当前类的其他方法时,可以使用this

  3. 在构造方法中引用当前对象:构造方法可以通过this()来调用同一个类的另一个构造方法。

  4. 在方法中引用当前对象本身:当需要将当前对象传递给其他方法时,可以使用this

使用this可以增强代码的可读性,并且当属性名或方法名与局部变量或参数名冲突时,this是一个很好的解决方式。

5.2 this的引用案例

1. 引用当前对象的属性

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {  
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;  
    <span style="color:#770088">private</span> <span style="color:#008855">int</span> <span style="color:#000000">age</span>;  
  
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>, <span style="color:#008855">int</span> <span style="color:#000000">age</span>) {  
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>; <span style="color:#aa5500">// 使用this引用当前对象的name属性  </span>
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>;   <span style="color:#aa5500">// 使用this引用当前对象的age属性  </span>
    }  
  
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setName</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {  
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>; <span style="color:#aa5500">// 使用this区分方法参数name和类的成员变量name  </span>
    }  
  
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setAge</span>(<span style="color:#008855">int</span> <span style="color:#000000">age</span>) {  
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>; <span style="color:#aa5500">// 使用this区分方法参数age和类的成员变量age  </span>
    }  
  
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">printInfo</span>() {  
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Name: "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">this</span>.<span style="color:#000000">name</span>);  
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Age: "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">this</span>.<span style="color:#000000">age</span>);  
    }  
}</span></span>

2. 在构造方法中引用当前对象的其他构造方法

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Circle</span> {  
    <span style="color:#770088">private</span> <span style="color:#008855">double</span> <span style="color:#000000">radius</span>;  
  
    <span style="color:#770088">public</span> <span style="color:#000000">Circle</span>(<span style="color:#008855">double</span> <span style="color:#000000">radius</span>) {  
        <span style="color:#770088">this</span>.<span style="color:#000000">radius</span> <span style="color:#981a1a">=</span> <span style="color:#000000">radius</span>;  
    }  
  
    <span style="color:#770088">public</span> <span style="color:#000000">Circle</span>() {  
        <span style="color:#770088">this</span>(<span style="color:#116644">1.0</span>); <span style="color:#aa5500">// 使用this调用另一个构造方法,为radius设置默认值  </span>
    }  
  
    <span style="color:#770088">public</span> <span style="color:#008855">double</span> <span style="color:#000000">getArea</span>() {  
        <span style="color:#770088">return</span> <span style="color:#000000">Math</span>.<span style="color:#000000">PI</span> <span style="color:#981a1a">*</span> <span style="color:#000000">radius</span> <span style="color:#981a1a">*</span> <span style="color:#000000">radius</span>;  
    }  
}</span></span>

3. 在方法中引用当前对象本身

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">MyObject</span> {  
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">doSomething</span>() {  
        <span style="color:#aa5500">// 假设有一个方法需要当前对象作为参数  </span>
        <span style="color:#000000">someOtherMethod</span>(<span style="color:#770088">this</span>); <span style="color:#aa5500">// 使用this引用当前对象本身  </span>
    }  
  
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">someOtherMethod</span>(<span style="color:#000000">MyObject</span> <span style="color:#000000">obj</span>) {  
        <span style="color:#aa5500">// 在这里处理obj对象,实际上处理的是调用doSomething的当前对象  </span>
    }  
}</span></span>

6 关键字:package、import

6.1 package(包)

package,称为包,用于指明该文件中定义的类、接口等结构所在的包。

6.1.1 语法格式

<span style="background-color:#f8f8f8"><span style="color:#333333">package 顶层包名.子包名 ;</span></span>

举例:pack1\pack2\PackageTest.java

<span style="background-color:#f8f8f8"><span style="color:#333333">package pack1.pack2; //指定类PackageTest属于包pack1.pack2
public class PackageTest{
public void display(){
System.out.println("in method display()");
}
}</span></span>

说明:

一个源文件只能有一个声明包的package语句

package语句作为Java源文件的第一条语句出现。若缺省该语句,则指定为无名包。

包名,属于标识符,满足标识符命名的规则和规范(全部小写)、见名知意

包通常使用所在公司域名的倒置:com.atguigu.xxx。

大家取包名时不要使用" java.xx "包

包对应于文件系统的目录,package语句中用 “.” 来指明包(目录)的层次,每.一次就表示一层文件目录。

同一个包下可以声明多个结构(类、接口),但是不能定义同名的结构(类、接口)。不同的包下

可以定义同名的结构(类、接口)

6.1.2 包的作用

包可以包含类和子包,划分 项目层次 ,便于管理

帮助 管理大型软件 系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式

解决 类命名冲突 的问题

控制 访问权限

6.2 import(导入)

为了使用定义在其它包中的Java类,需用import语句来显式引入指定包下所需要的类。相当于 import语

句告诉编译器到哪里去寻找这个类 。

6.2.1 语法格式

<span style="background-color:#f8f8f8"><span style="color:#333333">import 包名.类名;</span></span>

6.2.2 应用举例

<span style="background-color:#f8f8f8"><span style="color:#333333">import pack1.pack2.Test; //import pack1.pack2.*;表示引入pack1.pack2包中的所有结构
public class PackTest{
public static void main(String args[]){
Test t = new Test(); //Test类在pack1.pack2包中定义
t.display();
}
}</span></span>

6.2.3 注意事项

import语句,声明在包的声明和类的声明之间。

如果需要导入多个类或接口,那么就并列显式多个import语句即可

如果使用 a.* 导入结构,表示可以导入a包下的所有的结构。举例:可以使用java.util.*的方式,一

次性导入util包下所有的类或接口。

如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。

如果已经导入java.a包下的类,那么如果需要使用a包的子包下的类的话,仍然需要导入。

如果在代码中使用不同包下的同名的类,那么就需要使用类的全类名的方式指明调用的是哪个类。

(了解) import static 组合的使用:调用指定类或接口下的静态的属性或方法

7 继承

7.1 继承概述

继承(Inheritance)是面向对象编程(OOP)的一个重要特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。这样,子类可以重用父类的代码,减少代码重复,提高代码的可维护性和可扩展性。

7.2 继承的语法

在Java中,继承的语法非常简单。子类通过使用extends关键字来继承父类。例如:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">Parent</span> {
    <span style="color:#aa5500">// 父类的属性和方法</span>
}
​
<span style="color:#770088">class</span> <span style="color:#0000ff">Child</span> <span style="color:#770088">extends</span> <span style="color:#000000">Parent</span> {
    <span style="color:#aa5500">// 子类的属性和方法</span>
}</span></span>

7.3 代码举例

假设我们有一个Animal类,它有一个makeSound方法。现在我们想要创建一个Dog类,它也有makeSound方法。我们可以让Dog类继承Animal类,这样Dog类就自动拥有了makeSound方法。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">Animal</span> {
    <span style="color:#008855">void</span> <span style="color:#000000">makeSound</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"The animal makes a sound"</span>);
    }
}
​
<span style="color:#770088">class</span> <span style="color:#0000ff">Dog</span> <span style="color:#770088">extends</span> <span style="color:#000000">Animal</span> {
    <span style="color:#aa5500">// Dog类自动拥有了makeSound方法</span>
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Dog</span> <span style="color:#000000">myDog</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();
        <span style="color:#000000">myDog</span>.<span style="color:#000000">makeSound</span>(); <span style="color:#aa5500">// 输出:The animal makes a sound</span>
    }
}</span></span>

7.4 继承性细节说明

  1. 子类可以继承父类的属性和方法,但不能继承父类的构造方法。

  2. 子类可以覆盖(Override)父类的方法,以实现不同的功能。

  3. 子类可以访问父类的protectedpublic属性和方法,但不能访问父类的private属性和方法。

  4. Java不支持多重继承,即一个类不能继承多个父类。但可以通过接口实现多重继承的效果。

  5. 继承是一种is-a关系,即子类是父类的一种。例如,Dog类是Animal类的一种。

8 访问控制详细笔记

8.1 访问修饰符

  1. public:公共访问权限,表示类、属性和方法可以被任何其他类访问。

  2. protected:受保护的访问权限,表示类、属性和方法可以被同一个包内的类以及不同包内的子类访问。

  3. private:私有访问权限,表示类、属性和方法只能被本类访问。

  4. 默认(没有修饰符):表示类、属性和方法可以被同一个包内的类访问,但不能被不同包内的类访问。

    修饰符本类本包其他包子类其他包非子类
    private×××
    缺省√(本包子类非子类都可见)××
    protected√(本包子类非子类都可见)√(其他包仅限于子类中可见)×
    public

8.2 访问控制规则

  1. 类的访问权限可以是public或默认。public类可以被任何其他类访问;默认类只能被同一个包内的类访问。

  2. 属性和方法的访问权限可以是publicprotectedprivate或默认。public属性和方法可以被任何其他类访问;protected属性和方法可以被同一个包内的类以及不同包内的子类访问;private属性和方法只能被本类访问;默认属性和方法可以被同一个包内的类访问。

  3. 子类可以访问父类的protectedpublic属性和方法,但不能访问父类的private属性和方法。

  4. 在同一个包内,可以访问默认访问权限的类、属性和方法。

8.3 案例代码

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">// 文件名:AccessControlExample.java</span>
​
<span style="color:#aa5500">// 默认访问权限的类</span>
<span style="color:#770088">class</span> <span style="color:#0000ff">DefaultClass</span> {
    <span style="color:#aa5500">// 默认访问权限的属性</span>
    <span style="color:#008855">int</span> <span style="color:#000000">defaultField</span>;
​
    <span style="color:#aa5500">// 默认访问权限的方法</span>
    <span style="color:#008855">void</span> <span style="color:#000000">defaultMethod</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Default method in DefaultClass"</span>);
    }
}
​
<span style="color:#aa5500">// 公共访问权限的类</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">AccessControlExample</span> {
    <span style="color:#aa5500">// 公共访问权限的属性</span>
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">publicField</span>;
​
    <span style="color:#aa5500">// 受保护的访问权限的属性</span>
    <span style="color:#770088">protected</span> <span style="color:#008855">int</span> <span style="color:#000000">protectedField</span>;
​
    <span style="color:#aa5500">// 私有访问权限的属性</span>
    <span style="color:#770088">private</span> <span style="color:#008855">int</span> <span style="color:#000000">privateField</span>;
​
    <span style="color:#aa5500">// 公共访问权限的方法</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">publicMethod</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Public method in AccessControlExample"</span>);
    }
​
    <span style="color:#aa5500">// 受保护的访问权限的方法</span>
    <span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">protectedMethod</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Protected method in AccessControlExample"</span>);
    }
​
    <span style="color:#aa5500">// 私有访问权限的方法</span>
    <span style="color:#770088">private</span> <span style="color:#008855">void</span> <span style="color:#000000">privateMethod</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Private method in AccessControlExample"</span>);
    }
}
​
<span style="color:#aa5500">// 文件名:AccessControlDemo.java</span>
​
<span style="color:#770088">class</span> <span style="color:#0000ff">AccessControlDemo</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">AccessControlExample</span> <span style="color:#000000">example</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">AccessControlExample</span>();
​
        <span style="color:#aa5500">// 访问公共属性和方法</span>
        <span style="color:#000000">example</span>.<span style="color:#000000">publicField</span> <span style="color:#981a1a">=</span> <span style="color:#116644">1</span>;
        <span style="color:#000000">example</span>.<span style="color:#000000">publicMethod</span>();
​
        <span style="color:#aa5500">// 访问受保护的属性和方法(在同一个包内)</span>
        <span style="color:#000000">example</span>.<span style="color:#000000">protectedField</span> <span style="color:#981a1a">=</span> <span style="color:#116644">2</span>;
        <span style="color:#000000">example</span>.<span style="color:#000000">protectedMethod</span>();
​
        <span style="color:#aa5500">// 无法访问私有属性和方法</span>
        <span style="color:#aa5500">// example.privateField = 3; // 编译错误</span>
        <span style="color:#aa5500">// example.privateMethod(); // 编译错误</span>
​
        <span style="color:#aa5500">// 访问默认访问权限的类和其成员(在同一个包内)</span>
        <span style="color:#000000">DefaultClass</span> <span style="color:#000000">defaultClass</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">DefaultClass</span>();
        <span style="color:#000000">defaultClass</span>.<span style="color:#000000">defaultField</span> <span style="color:#981a1a">=</span> <span style="color:#116644">4</span>;
        <span style="color:#000000">defaultClass</span>.<span style="color:#000000">defaultMethod</span>();
    }
}</span></span>

9 方法的重写(override/overwrite)

父类的所有方法子类都会继承,但是当某个方法被继承到子类之后,子类觉得父类原来的实现不适合于自己当前的类,该怎么办呢?子类可以对从父类中继承来的方法进行改造,我们称为方法的重写 (override、overwrite)。也称为方法的重置覆盖

在程序执行时,子类的方法将覆盖父类的方法

9.1 方法重写举例

比如新的手机增加来电显示头像的功能,代码如下:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">inherited</span>.<span style="color:#000000">method</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Phone</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">sendMessage</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"发短信"</span>);
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">call</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"打电话"</span>);
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">showNum</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"来电显示号码"</span>);
    }
}
​</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">inherited</span>.<span style="color:#000000">method</span>;
​
<span style="color:#aa5500">//SmartPhone:智能手机</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmartPhone</span> <span style="color:#770088">extends</span> <span style="color:#000000">Phone</span>{
    <span style="color:#aa5500">//重写父类的来电显示功能的方法</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">showNum</span>(){
        <span style="color:#aa5500">//来电显示姓名和图片功能</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"显示来电姓名"</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"显示头像"</span>);
    }
    <span style="color:#aa5500">//重写父类的通话功能的方法</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">call</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"语音通话 或 视频通话"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">inherited</span>.<span style="color:#000000">method</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestOverride</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">// 创建子类对象</span>
        <span style="color:#000000">SmartPhone</span> <span style="color:#000000">sp</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">SmartPhone</span>();
​
        <span style="color:#aa5500">// 调用父类继承而来的方法</span>
        <span style="color:#000000">sp</span>.<span style="color:#000000">call</span>();
​
        <span style="color:#aa5500">// 调用子类重写的方法</span>
        <span style="color:#000000">sp</span>.<span style="color:#000000">showNum</span>();
    }
}</span></span>

9.2 方法重写的要求

  1. 子类重写的方法必须和父类被重写的方法具有相同的方法名称参数列表

  2. 子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型。(例如:Student < Person)。

注意:如果返回值类型是基本数据类型和void,那么必须是相同

  1. 子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限。(public > protected > 缺省 > private)

注意:① 父类私有方法不能重写 ② 跨包的父类缺省的方法也不能重写

  1. 子类方法抛出的异常不能大于父类被重写方法的异常

此外,子类与父类中同名同参数的方法必须同时声明为非static的(即为重写),或者同时声明为static的(不是重写)。因为static方法是属于类的,子类无法覆盖父类的方法。

9.3 方法的重载与重写

方法的重载:方法名相同,形参列表不同。不看返回值类型。

方法的重写:见上面。

(1)同一个类中

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">inherited</span>.<span style="color:#000000">method</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestOverload</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">max</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>, <span style="color:#008855">int</span> <span style="color:#000000">b</span>){
        <span style="color:#770088">return</span> <span style="color:#000000">a</span> <span style="color:#981a1a">></span> <span style="color:#000000">b</span> <span style="color:#981a1a">?</span> <span style="color:#000000">a</span> : <span style="color:#000000">b</span>;
    }
    <span style="color:#770088">public</span> <span style="color:#008855">double</span> <span style="color:#000000">max</span>(<span style="color:#008855">double</span> <span style="color:#000000">a</span>, <span style="color:#008855">double</span> <span style="color:#000000">b</span>){
        <span style="color:#770088">return</span> <span style="color:#000000">a</span> <span style="color:#981a1a">></span> <span style="color:#000000">b</span> <span style="color:#981a1a">?</span> <span style="color:#000000">a</span> : <span style="color:#000000">b</span>;
    }
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">max</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>, <span style="color:#008855">int</span> <span style="color:#000000">b</span>,<span style="color:#008855">int</span> <span style="color:#000000">c</span>){
        <span style="color:#770088">return</span> <span style="color:#000000">max</span>(<span style="color:#000000">max</span>(<span style="color:#000000">a</span>,<span style="color:#000000">b</span>),<span style="color:#000000">c</span>);
    }
}</span></span>

(2)父子类中

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">inherited</span>.<span style="color:#000000">method</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestOverloadOverride</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Son</span> <span style="color:#000000">s</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Son</span>();
        <span style="color:#000000">s</span>.<span style="color:#000000">method</span>(<span style="color:#116644">1</span>);<span style="color:#aa5500">//只有一个形式的method方法</span>
​
        <span style="color:#000000">Daughter</span> <span style="color:#000000">d</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Daughter</span>();
        <span style="color:#000000">d</span>.<span style="color:#000000">method</span>(<span style="color:#116644">1</span>);
        <span style="color:#000000">d</span>.<span style="color:#000000">method</span>(<span style="color:#116644">1</span>,<span style="color:#116644">2</span>);<span style="color:#aa5500">//有两个形式的method方法</span>
    }
}
​
<span style="color:#770088">class</span> <span style="color:#0000ff">Father</span>{
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(<span style="color:#008855">int</span> <span style="color:#000000">i</span>){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Father.method"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Son</span> <span style="color:#770088">extends</span> <span style="color:#000000">Father</span>{
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(<span style="color:#008855">int</span> <span style="color:#000000">i</span>){<span style="color:#aa5500">//重写</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Son.method"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Daughter</span> <span style="color:#770088">extends</span> <span style="color:#000000">Father</span>{
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(<span style="color:#008855">int</span> <span style="color:#000000">i</span>,<span style="color:#008855">int</span> <span style="color:#000000">j</span>){<span style="color:#aa5500">//重载</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Daughter.method"</span>);
    }
}</span></span>

10 super关键字

10.1 super的理解

在Java类中使用super来调用父类中的指定操作:

  • super可用于访问父类中定义的属性

  • super可用于调用父类中定义的成员方法

  • super可用于在子类构造器中调用父类的构造器

注意:

  • 尤其当子父类出现同名成员时,可以用super表明调用的是父类中的成员

  • super的追溯不仅限于直接父类

  • super和this的用法相像,this代表本类对象的引用,super代表父类的内存空间的标识

10.2 super的使用场景

10.2.1 子类中调用父类被重写的方法

  • 如果子类没有重写父类的方法,只要权限修饰符允许,在子类中完全可以直接调用父类的方法;

  • 如果子类重写了父类的方法,在子类中需要通过super.才能调用父类被重写的方法,否则默认调用的子类重写的方法

举例:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">inherited</span>.<span style="color:#000000">method</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Phone</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">sendMessage</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"发短信"</span>);
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">call</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"打电话"</span>);
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">showNum</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"来电显示号码"</span>);
    }
}
​
<span style="color:#aa5500">//smartphone:智能手机</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SmartPhone</span> <span style="color:#770088">extends</span> <span style="color:#000000">Phone</span>{
    <span style="color:#aa5500">//重写父类的来电显示功能的方法</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">showNum</span>(){
        <span style="color:#aa5500">//来电显示姓名和图片功能</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"显示来电姓名"</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"显示头像"</span>);
​
        <span style="color:#aa5500">//保留父类来电显示号码的功能</span>
        <span style="color:#770088">super</span>.<span style="color:#000000">showNum</span>();<span style="color:#aa5500">//此处必须加super.,否则就是无限递归,那么就会栈内存溢出</span>
    }
}</span></span>

总结:

  • 方法前面没有super.和this.

    • 先从子类找匹配方法,如果没有,再从直接父类找,再没有,继续往上追溯

  • 方法前面有this.

    • 先从子类找匹配方法,如果没有,再从直接父类找,再没有,继续往上追溯

  • 方法前面有super.

    • 从当前子类的直接父类找,如果没有,继续往上追溯

10.2.2 子类中调用父类中同名的成员变量

  • 如果实例变量与局部变量重名,可以在实例变量前面加this.进行区别

  • 如果子类实例变量和父类实例变量重名,并且父类的该实例变量在子类仍然可见,在子类中要访问父类声明的实例变量需要在父类实例变量前加super.,否则默认访问的是子类自己声明的实例变量

  • 如果父子类实例变量没有重名,只要权限修饰符允许,在子类中完全可以直接访问父类中声明的实例变量,也可以用this.实例访问,也可以用super.实例变量访问

举例:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">Father</span>{
    <span style="color:#008855">int</span> <span style="color:#000000">a</span> <span style="color:#981a1a">=</span> <span style="color:#116644">10</span>;
    <span style="color:#008855">int</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#116644">11</span>;
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Son</span> <span style="color:#770088">extends</span> <span style="color:#000000">Father</span>{
    <span style="color:#008855">int</span> <span style="color:#000000">a</span> <span style="color:#981a1a">=</span> <span style="color:#116644">20</span>;
    
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">test</span>(){
        <span style="color:#aa5500">//子类与父类的属性同名,子类对象中就有两个a</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"子类的a:"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">a</span>);<span style="color:#aa5500">//20  先找局部变量找,没有再从本类成员变量找</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"子类的a:"</span> <span style="color:#981a1a">+</span> <span style="color:#770088">this</span>.<span style="color:#000000">a</span>);<span style="color:#aa5500">//20   先从本类成员变量找</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"父类的a:"</span> <span style="color:#981a1a">+</span> <span style="color:#770088">super</span>.<span style="color:#000000">a</span>);<span style="color:#aa5500">//10    直接从父类成员变量找</span>
        
        <span style="color:#aa5500">//子类与父类的属性不同名,是同一个b</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"b = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">b</span>);<span style="color:#aa5500">//11  先找局部变量找,没有再从本类成员变量找,没有再从父类找</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"b = "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">this</span>.<span style="color:#000000">b</span>);<span style="color:#aa5500">//11   先从本类成员变量找,没有再从父类找</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"b = "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">super</span>.<span style="color:#000000">b</span>);<span style="color:#aa5500">//11  直接从父类局部变量找</span>
    }
    
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>, <span style="color:#008855">int</span> <span style="color:#000000">b</span>){
        <span style="color:#aa5500">//子类与父类的属性同名,子类对象中就有两个成员变量a,此时方法中还有一个局部变量a      </span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"局部变量的a:"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">a</span>);<span style="color:#aa5500">//30  先找局部变量</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"子类的a:"</span> <span style="color:#981a1a">+</span> <span style="color:#770088">this</span>.<span style="color:#000000">a</span>);<span style="color:#aa5500">//20  先从本类成员变量找</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"父类的a:"</span> <span style="color:#981a1a">+</span> <span style="color:#770088">super</span>.<span style="color:#000000">a</span>);<span style="color:#aa5500">//10  直接从父类成员变量找</span>
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"b = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">b</span>);<span style="color:#aa5500">//13  先找局部变量</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"b = "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">this</span>.<span style="color:#000000">b</span>);<span style="color:#aa5500">//11  先从本类成员变量找</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"b = "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">super</span>.<span style="color:#000000">b</span>);<span style="color:#aa5500">//11  直接从父类局部变量找</span>
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">Son</span> <span style="color:#000000">son</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Son</span>();
        <span style="color:#000000">son</span>.<span style="color:#000000">test</span>();
        <span style="color:#000000">son</span>.<span style="color:#000000">method</span>(<span style="color:#116644">30</span>,<span style="color:#116644">13</span>);  
    }
}</span></span>

总结:起点不同(就近原则)

  • 变量前面没有super.和this.

    • 在构造器、代码块、方法中如果出现使用某个变量,先查看是否是当前块声明的局部变量

    • 如果不是局部变量,先从当前执行代码的本类去找成员变量

    • 如果从当前执行代码的本类中没有找到,会往上找父类声明的成员变量(权限修饰符允许在子类中访问的)

  • 变量前面有this.

    • 通过this找成员变量时,先从当前执行代码的==本类去找成员变量==

    • 如果从当前执行代码的本类中没有找到,会往上找==父类声明的成员变量(==权限修饰符允许在子类中访问的)

  • 变量前面super.

    • 通过super找成员变量,直接从当前执行代码的直接父类去找成员变量(权限修饰符允许在子类中访问的)

    • 如果直接父类没有,就去父类的父类中找(权限修饰符允许在子类中访问的)

特别说明:应该避免子类声明和父类重名的成员变量

10.2.3 子类构造器中调用父类构造器

① 子类继承父类时,不会继承父类的构造器。只能通过“super(形参列表)”的方式调用父类指定的构造器。

② 规定:“super(形参列表)”,必须声明在构造器的首行。

③ 我们前面讲过,在构造器的首行可以使用"this(形参列表)",调用本类中重载的构造器, 结合②,结论:在构造器的首行,"this(形参列表)" 和 "super(形参列表)"只能二选一。

④ 如果在子类构造器的首行既没有显示调用"this(形参列表)",也没有显式调用"super(形参列表)", ​ 则子类此构造器默认调用"super()",即调用父类中空参的构造器。

⑤ 由③和④得到结论:子类的任何一个构造器中,要么会调用本类中重载的构造器,要么会调用父类的构造器。 只能是这两种情况之一。

⑥ 由⑤得到:一个类中声明有n个构造器,最多有n-1个构造器中使用了"this(形参列表)",则剩下的那个一定使用"super(形参列表)"。

开发中常见错误:

如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有空参的构造器,则编译出错

情景举例1:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
​
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
​
}
​
<span style="color:#770088">class</span> <span style="color:#0000ff">Test</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#aa5500">//A类和B类都是默认有一个无参构造,B类的默认无参构造中还会默认调用A类的默认无参构造</span>
        <span style="color:#aa5500">//但是因为都是默认的,没有打印语句,看不出来</span>
    }
}</span></span>

情景举例2:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
​
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#aa5500">//A类显示声明一个无参构造,</span>
        <span style="color:#aa5500">//B类默认有一个无参构造,</span>
        <span style="color:#aa5500">//B类的默认无参构造中会默认调用A类的无参构造</span>
        <span style="color:#aa5500">//可以看到会输出“A类无参构造器"</span>
    }
}</span></span>

情景举例3:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
    <span style="color:#000000">B</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#aa5500">//A类显示声明一个无参构造,</span>
        <span style="color:#aa5500">//B类显示声明一个无参构造,        </span>
        <span style="color:#aa5500">//B类的无参构造中虽然没有写super(),但是仍然会默认调用A类的无参构造</span>
        <span style="color:#aa5500">//可以看到会输出“A类无参构造器"和"B类无参构造器")</span>
    }
}</span></span>

情景举例4:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
    <span style="color:#000000">B</span>(){
        <span style="color:#770088">super</span>();
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#aa5500">//A类显示声明一个无参构造,</span>
        <span style="color:#aa5500">//B类显示声明一个无参构造,        </span>
        <span style="color:#aa5500">//B类的无参构造中明确写了super(),表示调用A类的无参构造</span>
        <span style="color:#aa5500">//可以看到会输出“A类无参构造器"和"B类无参构造器")</span>
    }
}</span></span>

情景举例5:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类有参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
    <span style="color:#000000">B</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test05</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#aa5500">//A类显示声明一个有参构造,没有写无参构造,那么A类就没有无参构造了</span>
        <span style="color:#aa5500">//B类显示声明一个无参构造,        </span>
        <span style="color:#aa5500">//B类的无参构造没有写super(...),表示默认调用A类的无参构造</span>
        <span style="color:#aa5500">//编译报错,因为A类没有无参构造</span>
    }
}</span></span>

情景举例6:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类有参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
    <span style="color:#000000">B</span>(){
        <span style="color:#770088">super</span>();
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类无参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test06</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#aa5500">//A类显示声明一个有参构造,没有写无参构造,那么A类就没有无参构造了</span>
        <span style="color:#aa5500">//B类显示声明一个无参构造,        </span>
        <span style="color:#aa5500">//B类的无参构造明确写super(),表示调用A类的无参构造</span>
        <span style="color:#aa5500">//编译报错,因为A类没有无参构造</span>
    }
}</span></span>

情景举例7:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类有参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
    <span style="color:#000000">B</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>){
        <span style="color:#770088">super</span>(<span style="color:#000000">a</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类有参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test07</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>(<span style="color:#116644">10</span>);
        <span style="color:#aa5500">//A类显示声明一个有参构造,没有写无参构造,那么A类就没有无参构造了</span>
        <span style="color:#aa5500">//B类显示声明一个有参构造,        </span>
        <span style="color:#aa5500">//B类的有参构造明确写super(a),表示调用A类的有参构造</span>
        <span style="color:#aa5500">//会打印“A类有参构造器"和"B类有参构造器"</span>
    }
}</span></span>

情景举例8:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span>{
    <span style="color:#000000">A</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类无参构造器"</span>);
    }
    <span style="color:#000000">A</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"A类有参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">B</span> <span style="color:#770088">extends</span> <span style="color:#000000">A</span>{
    <span style="color:#000000">B</span>(){
        <span style="color:#770088">super</span>();<span style="color:#aa5500">//可以省略,调用父类的无参构造</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类无参构造器"</span>);
    }
    <span style="color:#000000">B</span>(<span style="color:#008855">int</span> <span style="color:#000000">a</span>){
        <span style="color:#770088">super</span>(<span style="color:#000000">a</span>);<span style="color:#aa5500">//调用父类有参构造</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"B类有参构造器"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Test8</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#000000">B</span> <span style="color:#000000">b1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>();
        <span style="color:#000000">B</span> <span style="color:#000000">b2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">B</span>(<span style="color:#116644">10</span>);
    }
}</span></span>

10.3 小结:this与super

1、this和super的意义

this:当前对象

  • 在构造器和非静态代码块中,表示正在new的对象

  • 在实例方法中,表示调用当前方法的对象

super:引用父类声明的成员

2、this和super的使用格式

  • this

    • this.成员变量:表示当前对象的某个成员变量,而不是局部变量

    • this.成员方法:表示当前对象的某个成员方法,完全可以省略this.

    • this()或this(实参列表):调用另一个构造器协助当前对象的实例化,只能在构造器首行,只会找本类的构造器,找不到就报错

  • super

    • super.成员变量:表示当前对象的某个成员变量,该成员变量在父类中声明的

    • super.成员方法:表示当前对象的某个成员方法,该成员方法在父类中声明的

    • super()或super(实参列表):调用父类的构造器协助当前对象的实例化,只能在构造器首行,只会找直接父类的对应构造器,找不到就报错

11 多态性

一千个读者眼中有一千个哈姆雷特。

11.1 多态的形式和体现

11.1.1 对象的多态性

多态性,是面向对象中最重要的概念,在Java中的体现:对象的多态性:父类的引用指向子类的对象

格式:(父类类型:指子类继承的父类类型,或者实现的接口类型)

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">父类类型</span> <span style="color:#000000">变量名</span> <span style="color:#981a1a">=</span> <span style="color:#000000">子类对象;</span></span></span>

举例:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">Person</span> <span style="color:#000000">p</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Student</span>();
​
<span style="color:#008855">Object</span> <span style="color:#000000">o</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>();<span style="color:#aa5500">//Object类型的变量o,指向Person类型的对象</span>
​
<span style="color:#000000">o</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Student</span>(); <span style="color:#aa5500">//Object类型的变量o,指向Student类型的对象</span></span></span>

对象的多态:在Java中,子类的对象可以替代父类的对象使用。所以,一个引用类型变量可能指向(引用)多种不同类型的对象

11.1.2 多态的理解

Java引用变量有两个类型:编译时类型运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看左边;运行时,看右边。

  • 若编译时类型和运行时类型不一致,就出现了对象的多态性(Polymorphism)

  • 多态情况下,“看左边”:看的是父类的引用(父类中不具备子类特有的方法) “看右边”:看的是子类的对象(实际运行的是子类重写父类的方法)

多态的使用前提:① 类的继承关系 ② 方法的重写

11.1.3 举例

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Pet</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">nickname</span>; <span style="color:#aa5500">//昵称</span>
​
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getNickname</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">nickname</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setNickname</span>(<span style="color:#008855">String</span> <span style="color:#000000">nickname</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">nickname</span> <span style="color:#981a1a">=</span> <span style="color:#000000">nickname</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">nickname</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">"吃东西"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Cat</span> <span style="color:#770088">extends</span> <span style="color:#000000">Pet</span> {
    <span style="color:#aa5500">//子类重写父类的方法</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"猫咪"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">getNickname</span>() <span style="color:#981a1a">+</span> <span style="color:#aa1111">"吃鱼仔"</span>);
    }
​
    <span style="color:#aa5500">//子类扩展的方法</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">catchMouse</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"抓老鼠"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Dog</span> <span style="color:#770088">extends</span> <span style="color:#000000">Pet</span> {
    <span style="color:#aa5500">//子类重写父类的方法</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"狗子"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">getNickname</span>() <span style="color:#981a1a">+</span> <span style="color:#aa1111">"啃骨头"</span>);
    }
​
    <span style="color:#aa5500">//子类扩展的方法</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">watchHouse</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"看家"</span>);
    }
}</span></span>

1、方法内局部变量的赋值体现多态

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestPet</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">//多态引用</span>
        <span style="color:#000000">Pet</span> <span style="color:#000000">pet</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();
        <span style="color:#000000">pet</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"小白"</span>);
​
        <span style="color:#aa5500">//多态的表现形式</span>
        <span style="color:#aa5500">/*</span>
        <span style="color:#aa5500">编译时看父类:只能调用父类声明的方法,不能调用子类扩展的方法;</span>
        <span style="color:#aa5500">运行时,看“子类”,如果子类重写了方法,一定是执行子类重写的方法体;</span>
         <span style="color:#aa5500">*/</span>
        <span style="color:#000000">pet</span>.<span style="color:#000000">eat</span>();<span style="color:#aa5500">//运行时执行子类Dog重写的方法</span>
<span style="color:#aa5500">//      pet.watchHouse();//不能调用Dog子类扩展的方法</span>
​
        <span style="color:#000000">pet</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Cat</span>();
        <span style="color:#000000">pet</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"雪球"</span>);
        <span style="color:#000000">pet</span>.<span style="color:#000000">eat</span>();<span style="color:#aa5500">//运行时执行子类Cat重写的方法</span>
    }
}</span></span>

2、方法的形参声明体现多态

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span>{
    <span style="color:#770088">private</span> <span style="color:#000000">Pet</span> <span style="color:#000000">pet</span>;
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">adopt</span>(<span style="color:#000000">Pet</span> <span style="color:#000000">pet</span>) {<span style="color:#aa5500">//形参是父类类型,实参是子类对象</span>
        <span style="color:#770088">this</span>.<span style="color:#000000">pet</span> <span style="color:#981a1a">=</span> <span style="color:#000000">pet</span>;
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">feed</span>(){
        <span style="color:#000000">pet</span>.<span style="color:#000000">eat</span>();<span style="color:#aa5500">//pet实际引用的对象类型不同,执行的eat方法也不同</span>
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestPerson</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>();
​
        <span style="color:#000000">Dog</span> <span style="color:#000000">dog</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();
        <span style="color:#000000">dog</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"小白"</span>);
        <span style="color:#000000">person</span>.<span style="color:#000000">adopt</span>(<span style="color:#000000">dog</span>);<span style="color:#aa5500">//实参是dog子类对象,形参是父类Pet类型</span>
        <span style="color:#000000">person</span>.<span style="color:#000000">feed</span>();
​
        <span style="color:#000000">Cat</span> <span style="color:#000000">cat</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Cat</span>();
        <span style="color:#000000">cat</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"雪球"</span>);
        <span style="color:#000000">person</span>.<span style="color:#000000">adopt</span>(<span style="color:#000000">cat</span>);<span style="color:#aa5500">//实参是cat子类对象,形参是父类Pet类型</span>
        <span style="color:#000000">person</span>.<span style="color:#000000">feed</span>();
    }
}</span></span>

3、方法返回值类型体现多态

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">PetShop</span> {
    <span style="color:#aa5500">//返回值类型是父类类型,实际返回的是子类对象</span>
    <span style="color:#770088">public</span> <span style="color:#000000">Pet</span> <span style="color:#000000">sale</span>(<span style="color:#008855">String</span> <span style="color:#000000">type</span>){
        <span style="color:#770088">switch</span> (<span style="color:#000000">type</span>){
            <span style="color:#770088">case</span> <span style="color:#aa1111">"Dog"</span>:
                <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();
            <span style="color:#770088">case</span> <span style="color:#aa1111">"Cat"</span>:
                <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">Cat</span>();
        }
        <span style="color:#770088">return</span> <span style="color:#221199">null</span>;
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestPetShop</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">PetShop</span> <span style="color:#000000">shop</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">PetShop</span>();
​
        <span style="color:#000000">Pet</span> <span style="color:#000000">dog</span> <span style="color:#981a1a">=</span> <span style="color:#000000">shop</span>.<span style="color:#000000">sale</span>(<span style="color:#aa1111">"Dog"</span>);
        <span style="color:#000000">dog</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"小白"</span>);
        <span style="color:#000000">dog</span>.<span style="color:#000000">eat</span>();
​
        <span style="color:#000000">Pet</span> <span style="color:#000000">cat</span> <span style="color:#981a1a">=</span> <span style="color:#000000">shop</span>.<span style="color:#000000">sale</span>(<span style="color:#aa1111">"Cat"</span>);
        <span style="color:#000000">cat</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"雪球"</span>);
        <span style="color:#000000">cat</span>.<span style="color:#000000">eat</span>();
    }
}</span></span>

11.2 为什么需要多态性(polymorphism)?

开发中,有时我们在设计一个数组、或一个成员变量、或一个方法的形参、返回值类型时,无法确定它具体的类型,只能确定它是某个系列的类型。

案例:

(1)声明一个Dog类,包含public void eat()方法,输出“狗啃骨头”

(2)声明一个Cat类,包含public void eat()方法,输出“猫吃鱼仔”

(3)声明一个Person类,功能如下:

  • 包含宠物属性

  • 包含领养宠物方法 public void adopt(宠物类型Pet)

  • 包含喂宠物吃东西的方法 public void feed(),实现为调用宠物对象.eat()方法

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Dog</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"狗啃骨头"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Cat</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"猫吃鱼仔"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#000000">Dog</span> <span style="color:#000000">dog</span>;
​
    <span style="color:#aa5500">//adopt:领养</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">adopt</span>(<span style="color:#000000">Dog</span> <span style="color:#000000">dog</span>){
        <span style="color:#770088">this</span>.<span style="color:#000000">dog</span> <span style="color:#981a1a">=</span> <span style="color:#000000">dog</span>;
    }
​
    <span style="color:#aa5500">//feed:喂食</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">feed</span>(){
        <span style="color:#770088">if</span>(<span style="color:#000000">dog</span> <span style="color:#981a1a">!=</span> <span style="color:#221199">null</span>){
            <span style="color:#000000">dog</span>.<span style="color:#000000">eat</span>();
        }
    }
    <span style="color:#aa5500">/*</span>
    <span style="color:#aa5500">问题:</span>
    <span style="color:#aa5500">1、从养狗切换到养猫怎么办?   </span>
        <span style="color:#aa5500">修改代码把Dog修改为养猫?</span>
    <span style="color:#aa5500">2、或者有的人养狗,有的人养猫怎么办?  </span>
    <span style="color:#aa5500">3、要是还有更多其他宠物类型怎么办?</span>
    <span style="color:#aa5500">如果Java不支持多态,那么上面的问题将会非常麻烦,代码维护起来很难,扩展性很差。</span>
    <span style="color:#aa5500">*/</span>
}</span></span>

11.3 多态的好处和弊端

好处:变量引用的子类对象不同,执行的方法就不同,实现动态绑定。代码编写更灵活、功能更强大,可维护性和扩展性更好了。

弊端:一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">Student</span> <span style="color:#000000">m</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Student</span>();
<span style="color:#000000">m</span>.<span style="color:#000000">school</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"pku"</span>;   <span style="color:#aa5500">//合法,Student类有school成员变量</span>
<span style="color:#000000">Person</span> <span style="color:#000000">e</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Student</span>(); 
<span style="color:#000000">e</span>.<span style="color:#000000">school</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"pku"</span>;   <span style="color:#aa5500">//非法,Person类没有school成员变量</span>
​
<span style="color:#aa5500">// 属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编译错误。</span></span></span>

12 向上转型与向下转型

首先,一个对象在new的时候创建是哪个类型的对象,它从头至尾都不会变。即这个对象的运行时类型,本质的类型用于不会变。但是,把这个对象赋值给不同类型的变量时,这些变量的编译时类型却不同。

12.1 为什么要类型转换

因为多态,就一定会有把子类对象赋值给父类变量的时候,这个时候,在编译期间,就会出现类型转换的现象。

但是,使用父类变量接收了子类对象之后,我们就不能调用子类拥有,而父类没有的方法了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做类型转换,使得编译通过

  • 向上转型:当左边的变量的类型(父类) > 右边对象/变量的类型(子类),我们就称为向上转型

    • 此时,编译时按照左边变量的类型处理,就只能调用父类中有的变量和方法,不能调用子类特有的变量和方法了

    • 但是,运行时,仍然是对象本身的类型,所以执行的方法是子类重写的方法体。

    • 此时,一定是安全的,而且也是自动完成的

  • 向下转型:当左边的变量的类型(子类)<右边对象/变量的编译时类型(父类),我们就称为向下转型

    • 此时,编译时按照左边变量的类型处理,就可以调用子类特有的变量和方法了

    • 但是,运行时,仍然是对象本身的类型

    • 不是所有通过编译的向下转型都是正确的,可能会发生ClassCastException,为了安全,可以通过isInstanceof关键字进行判断

12.2 如何向上或向下转型

向上转型:自动完成

向下转型:(子类类型)父类变量

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ClassCastTest</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">//没有类型转换</span>
        <span style="color:#000000">Dog</span> <span style="color:#000000">dog</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();<span style="color:#aa5500">//dog的编译时类型和运行时类型都是Dog</span>
​
        <span style="color:#aa5500">//向上转型</span>
        <span style="color:#000000">Pet</span> <span style="color:#000000">pet</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();<span style="color:#aa5500">//pet的编译时类型是Pet,运行时类型是Dog</span>
        <span style="color:#000000">pet</span>.<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"小白"</span>);
        <span style="color:#000000">pet</span>.<span style="color:#000000">eat</span>();<span style="color:#aa5500">//可以调用父类Pet有声明的方法eat,但执行的是子类重写的eat方法体</span>
<span style="color:#aa5500">//        pet.watchHouse();//不能调用父类没有的方法watchHouse</span>
​
        <span style="color:#000000">Dog</span> <span style="color:#000000">d</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Dog</span>) <span style="color:#000000">pet</span>;
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"d.nickname = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">d</span>.<span style="color:#000000">getNickname</span>());
        <span style="color:#000000">d</span>.<span style="color:#000000">eat</span>();<span style="color:#aa5500">//可以调用eat方法</span>
        <span style="color:#000000">d</span>.<span style="color:#000000">watchHouse</span>();<span style="color:#aa5500">//可以调用子类扩展的方法watchHouse</span>
​
        <span style="color:#000000">Cat</span> <span style="color:#000000">c</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Cat</span>) <span style="color:#000000">pet</span>;<span style="color:#aa5500">//编译通过,因为从语法检查来说,pet的编译时类型是Pet,Cat是Pet的子类,所以向下转型语法正确</span>
        <span style="color:#aa5500">//这句代码运行报错ClassCastException,因为pet变量的运行时类型是Dog,Dog和Cat之间是没有继承关系的</span>
    }
}</span></span>

12.3 instanceof关键字

为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验。如下代码格式:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//检验对象a是否是数据类型A的对象,返回值为boolean型</span>
<span style="color:#000000">对象a</span> <span style="color:#770088">instanceof</span> <span style="color:#000000">数据类型A</span> </span></span>
  • 说明:

    • 只要用instanceof判断返回true的,那么强转为该类型就一定是安全的,不会报ClassCastException异常。

    • 如果对象a属于类A的子类B,a instanceof A值也为true。

    • 要求对象a所属的类与类A必须是子类和父类的关系,否则编译错误。

代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">polymorphism</span>.<span style="color:#000000">grammar</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestInstanceof</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Pet</span>[] <span style="color:#000000">pets</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Pet</span>[<span style="color:#116644">2</span>];
        <span style="color:#000000">pets</span>[<span style="color:#116644">0</span>] <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Dog</span>();<span style="color:#aa5500">//多态引用</span>
        <span style="color:#000000">pets</span>[<span style="color:#116644">0</span>].<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"小白"</span>);
        <span style="color:#000000">pets</span>[<span style="color:#116644">1</span>] <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Cat</span>();<span style="color:#aa5500">//多态引用</span>
        <span style="color:#000000">pets</span>[<span style="color:#116644">1</span>].<span style="color:#000000">setNickname</span>(<span style="color:#aa1111">"雪球"</span>);
​
        <span style="color:#770088">for</span> (<span style="color:#008855">int</span> <span style="color:#000000">i</span> <span style="color:#981a1a">=</span> <span style="color:#116644">0</span>; <span style="color:#000000">i</span> <span style="color:#981a1a"><</span> <span style="color:#000000">pets</span>.<span style="color:#000000">length</span>; <span style="color:#000000">i</span><span style="color:#981a1a">++</span>) {
            <span style="color:#000000">pets</span>[<span style="color:#000000">i</span>].<span style="color:#000000">eat</span>();
​
            <span style="color:#770088">if</span>(<span style="color:#000000">pets</span>[<span style="color:#000000">i</span>] <span style="color:#770088">instanceof</span> <span style="color:#000000">Dog</span>){
                <span style="color:#000000">Dog</span> <span style="color:#000000">dog</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Dog</span>) <span style="color:#000000">pets</span>[<span style="color:#000000">i</span>];
                <span style="color:#000000">dog</span>.<span style="color:#000000">watchHouse</span>();
            }<span style="color:#770088">else</span> <span style="color:#770088">if</span>(<span style="color:#000000">pets</span>[<span style="color:#000000">i</span>] <span style="color:#770088">instanceof</span> <span style="color:#000000">Cat</span>){
                <span style="color:#000000">Cat</span> <span style="color:#000000">cat</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Cat</span>) <span style="color:#000000">pets</span>[<span style="color:#000000">i</span>];
                <span style="color:#000000">cat</span>.<span style="color:#000000">catchMouse</span>();
            }
        }
    }
}</span></span>

13 object

在Java中,Object类是所有类的根父类,它包含了一些基本的方法,这些方法可以被所有的Java对象使用

13.1 理解根父类

在Java中,所有的类都是Object类的子类。这意味着,如果你创建一个新的类,它将自动继承Object类的所有方法。这使得你可以在任何对象上调用这些方法。

13.2 Object类的方法

13.2.1 equals()

equals()方法用于比较两个对象是否相等。默认情况下,equals()方法比较的是两个对象的引用,即它们是否指向同一个对象。然而,你可以重写equals()方法,以便根据对象的内容进行比较。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">equals</span>(<span style="color:#008855">Object</span> <span style="color:#000000">obj</span>) {
        <span style="color:#770088">if</span> (<span style="color:#770088">this</span> <span style="color:#981a1a">==</span> <span style="color:#000000">obj</span>) {
            <span style="color:#770088">return</span> <span style="color:#221199">true</span>;
        }
        <span style="color:#770088">if</span> (<span style="color:#000000">obj</span> <span style="color:#981a1a">==</span> <span style="color:#221199">null</span> <span style="color:#981a1a">||</span> <span style="color:#000000">getClass</span>() <span style="color:#981a1a">!=</span> <span style="color:#000000">obj</span>.<span style="color:#000000">getClass</span>()) {
            <span style="color:#770088">return</span> <span style="color:#221199">false</span>;
        }
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Person</span>) <span style="color:#000000">obj</span>;
        <span style="color:#770088">return</span> <span style="color:#000000">Objects</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">name</span>, <span style="color:#000000">person</span>.<span style="color:#000000">name</span>);
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">Person</span> <span style="color:#000000">person2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">Person</span> <span style="color:#000000">person3</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Bob"</span>);
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person1</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">person2</span>)); <span style="color:#aa5500">// 输出:true</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person1</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">person3</span>)); <span style="color:#aa5500">// 输出:false</span>
    }
}</span></span>

13.2.2 toString()

toString()方法用于返回对象的字符串表示。默认情况下,toString()方法返回对象的类名、@符号和对象的哈希码的无符号十六进制表示。你可以重写toString()方法,以便返回对象的更有意义的字符串表示。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">toString</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"Person{"</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">"name='"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">'\''</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">'}'</span>;
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person</span>.<span style="color:#000000">toString</span>()); <span style="color:#aa5500">// 输出:Person{name='Alice'}</span>
    }
}</span></span>

13.2.3 clone()

clone()方法用于创建并返回一个对象的副本。默认情况下,clone()方法是受保护的,并且抛出CloneNotSupportedException异常。要使用clone()方法,你需要实现Cloneable接口,并重写clone()方法。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> <span style="color:#770088">implements</span> <span style="color:#000000">Cloneable</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">protected</span> <span style="color:#008855">Object</span> <span style="color:#000000">clone</span>() <span style="color:#770088">throws</span> <span style="color:#000000">CloneNotSupportedException</span> {
        <span style="color:#770088">return</span> <span style="color:#770088">super</span>.<span style="color:#000000">clone</span>();
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#770088">try</span> {
            <span style="color:#000000">Person</span> <span style="color:#000000">person2</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Person</span>) <span style="color:#000000">person1</span>.<span style="color:#000000">clone</span>();
            <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person1</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">person2</span>)); <span style="color:#aa5500">// 输出:true</span>
        } <span style="color:#770088">catch</span> (<span style="color:#000000">CloneNotSupportedException</span> <span style="color:#000000">e</span>) {
            <span style="color:#000000">e</span>.<span style="color:#000000">printStackTrace</span>();
        }
    }
}</span></span>

13.2.4 finalize()

finalize()方法在对象被垃圾回收器回收之前调用。你可以重写finalize()方法,以便在对象被回收时执行一些清理操作。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">protected</span> <span style="color:#008855">void</span> <span style="color:#000000">finalize</span>() <span style="color:#770088">throws</span> <span style="color:#000000">Throwable</span> {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Person对象被回收"</span>);
        <span style="color:#770088">super</span>.<span style="color:#000000">finalize</span>();
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#221199">null</span>;
        <span style="color:#000000">System</span>.<span style="color:#000000">gc</span>(); <span style="color:#aa5500">// 提示JVM执行垃圾回收</span>
    }
}</span></span>

13.2.5 getClass()

getClass()方法返回对象的运行时类。这个方法对于获取对象的类信息非常有用。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">Class</span><span style="color:#981a1a"><?></span> <span style="color:#000000">personClass</span> <span style="color:#981a1a">=</span> <span style="color:#000000">person</span>.<span style="color:#000000">getClass</span>();
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">personClass</span>.<span style="color:#000000">getName</span>()); <span style="color:#aa5500">// 输出:Person</span>
    }
}</span></span>

13.2.6 hashCode()

hashCode()方法返回对象的哈希码。哈希码是一个整数,用于在哈希表等数据结构中快速查找对象。默认情况下,hashCode()方法返回对象的内存地址的哈希码。你可以重写hashCode()方法,以便根据对象的内容计算哈希码。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">hashCode</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">Objects</span>.<span style="color:#000000">hash</span>(<span style="color:#000000">name</span>);
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">Person</span> <span style="color:#000000">person2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">Person</span> <span style="color:#000000">person3</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Bob"</span>);
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person1</span>.<span style="color:#000000">hashCode</span>()); <span style="color:#aa5500">// 输出:1003660870</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person2</span>.<span style="color:#000000">hashCode</span>()); <span style="color:#aa5500">// 输出:1003660870</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person3</span>.<span style="color:#000000">hashCode</span>()); <span style="color:#aa5500">// 输出:1003660869</span>
    }
}</span></span>

14 equals方法与==

14.1 ==操作符

==操作符用于比较两个对象的引用是否指向内存中的同一个位置,也就是说,它比较的是两个对象的内存地址是否相同。如果比较的是基本数据类型(如int、double等),那么==会比较它们的值是否相等。

案例1:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#008855">Integer</span> <span style="color:#000000">a</span> <span style="color:#981a1a">=</span> <span style="color:#116644">127</span>;  
<span style="color:#008855">Integer</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#116644">127</span>;  
<span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">a</span> <span style="color:#981a1a">==</span> <span style="color:#000000">b</span>);  <span style="color:#aa5500">// 输出 true,因为a和b指向同一个Integer对象(在-128到127范围内,Integer对象会被缓存)  </span>
  
<span style="color:#008855">Integer</span> <span style="color:#000000">c</span> <span style="color:#981a1a">=</span> <span style="color:#116644">128</span>;  
<span style="color:#008855">Integer</span> <span style="color:#000000">d</span> <span style="color:#981a1a">=</span> <span style="color:#116644">128</span>;  
<span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">c</span> <span style="color:#981a1a">==</span> <span style="color:#000000">d</span>);  <span style="color:#aa5500">// 输出 false,因为c和d指向不同的Integer对象(超出缓存范围)  </span>
  
<span style="color:#008855">String</span> <span style="color:#000000">s1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#008855">String</span>(<span style="color:#aa1111">"hello"</span>);  
<span style="color:#008855">String</span> <span style="color:#000000">s2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#008855">String</span>(<span style="color:#aa1111">"hello"</span>);  
<span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">s1</span> <span style="color:#981a1a">==</span> <span style="color:#000000">s2</span>);  <span style="color:#aa5500">// 输出 false,因为s1和s2指向不同的String对象,即使它们的内容相同</span></span></span>

14.2 equals()方法

equals()方法是Object类的一个方法,用于比较两个对象的内容是否相等。默认情况下,equals()方法的行为和==相同,比较的是对象的内存地址。但是,许多类(如String、Integer等)都重写了equals()方法,使其能够比较对象的内容。

案例1:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#008855">String</span> <span style="color:#000000">s1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#008855">String</span>(<span style="color:#aa1111">"hello"</span>);  
<span style="color:#008855">String</span> <span style="color:#000000">s2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#008855">String</span>(<span style="color:#aa1111">"hello"</span>);  
<span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">s1</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">s2</span>));  <span style="color:#aa5500">// 输出 true,因为s1和s2的内容相同  </span>
  
<span style="color:#000000">Person</span> <span style="color:#000000">p1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>, <span style="color:#116644">25</span>);  
<span style="color:#000000">Person</span> <span style="color:#000000">p2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>, <span style="color:#116644">25</span>);  
<span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">p1</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">p2</span>));  <span style="color:#aa5500">// 默认情况下输出 false,因为Person类没有重写equals方法,比较的是内存地址</span></span></span>

案例2:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {  
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;  
    <span style="color:#770088">private</span> <span style="color:#008855">int</span> <span style="color:#000000">age</span>;  
  
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>, <span style="color:#008855">int</span> <span style="color:#000000">age</span>) {  
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;  
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>;  
    }  
  
    <span style="color:#555555">@Override</span>  
    <span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">equals</span>(<span style="color:#008855">Object</span> <span style="color:#000000">obj</span>) {  
        <span style="color:#770088">if</span> (<span style="color:#770088">this</span> <span style="color:#981a1a">==</span> <span style="color:#000000">obj</span>) <span style="color:#770088">return</span> <span style="color:#221199">true</span>;  
        <span style="color:#770088">if</span> (<span style="color:#000000">obj</span> <span style="color:#981a1a">==</span> <span style="color:#221199">null</span> <span style="color:#981a1a">||</span> <span style="color:#000000">getClass</span>() <span style="color:#981a1a">!=</span> <span style="color:#000000">obj</span>.<span style="color:#000000">getClass</span>()) <span style="color:#770088">return</span> <span style="color:#221199">false</span>;  
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> (<span style="color:#000000">Person</span>) <span style="color:#000000">obj</span>;  
        <span style="color:#770088">return</span> <span style="color:#000000">age</span> <span style="color:#981a1a">==</span> <span style="color:#000000">person</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">&&</span>  
                <span style="color:#000000">Objects</span>.<span style="color:#000000">equals</span>(<span style="color:#000000">name</span>, <span style="color:#000000">person</span>.<span style="color:#000000">name</span>);  
    }  
  
    <span style="color:#555555">@Override</span>  
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">hashCode</span>() {  
        <span style="color:#770088">return</span> <span style="color:#000000">Objects</span>.<span style="color:#000000">hash</span>(<span style="color:#000000">name</span>, <span style="color:#000000">age</span>);  
    }  
}</span></span>

15 toString方法

在Java中,toString()方法是Object类的一个方法,它用于返回对象的字符串表示

15.1 默认实现

toString()方法的默认实现返回对象的类名、@符号和对象的哈希码的无符号十六进制表示。这对于调试和日志记录等场景可能是有用的,但通常不适合直接展示给用户。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person</span>.<span style="color:#000000">toString</span>()); <span style="color:#aa5500">// 输出:Person@15db9742</span>
    }
}</span></span>

15.2 重写toString()方法

为了提供更有意义的字符串表示,你可以在自定义类中重写toString()方法。以下是一个例子:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">toString</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"Person{"</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">"name='"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">'\''</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">'}'</span>;
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">person</span>.<span style="color:#000000">toString</span>()); <span style="color:#aa5500">// 输出:Person{name='Alice'}</span>
    }
}</span></span>

15.3 使用toString()方法进行字符串拼接

toString()方法在进行字符串拼接时非常有用。以下是一个例子:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Person</span> {
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
    <span style="color:#770088">private</span> <span style="color:#008855">int</span> <span style="color:#000000">age</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Person</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>, <span style="color:#008855">int</span> <span style="color:#000000">age</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">toString</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"Person{"</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">"name='"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">'\''</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">", age="</span> <span style="color:#981a1a">+</span> <span style="color:#000000">age</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">'}'</span>;
    }
}
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Person</span> <span style="color:#000000">person</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Person</span>(<span style="color:#aa1111">"Alice"</span>, <span style="color:#116644">30</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Person info: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">person</span>.<span style="color:#000000">toString</span>()); <span style="color:#aa5500">// 输出:Person info: Person{name='Alice', age=30}</span>
    }
}</span></span>

16 封装类

在Java中,包装类(Wrapper class)是一种数据类型,它将基本数据类型(如intdouble等)封装成对象

16.1 基本数据类型与包装类的对应关系

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

16.2 自动装箱与拆箱

Java 5引入了自动装箱(Autoboxing)和拆箱(Unboxing)特性。这意味着你可以在需要时自动地将基本数据类型转换为包装类对象,或者将包装类对象转换为基本数据类型。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#008855">Integer</span> <span style="color:#000000">num1</span> <span style="color:#981a1a">=</span> <span style="color:#116644">42</span>; <span style="color:#aa5500">// 自动装箱:int -> Integer</span>
        <span style="color:#008855">int</span> <span style="color:#000000">num2</span> <span style="color:#981a1a">=</span> <span style="color:#000000">num1</span>;   <span style="color:#aa5500">// 自动拆箱:Integer -> int</span>
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"num1: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">num1</span>); <span style="color:#aa5500">// 输出:num1: 42</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"num2: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">num2</span>); <span style="color:#aa5500">// 输出:num2: 42</span>
    }
}</span></span>

16.3 使用包装类进行类型转换

包装类提供了一些静态方法,用于在不同的数值类型之间进行转换。例如,Integer类提供了toBinaryString()toHexString()等方法,用于将整数转换为二进制或十六进制字符串。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#008855">int</span> <span style="color:#000000">num</span> <span style="color:#981a1a">=</span> <span style="color:#116644">42</span>;
        <span style="color:#008855">String</span> <span style="color:#000000">binaryString</span> <span style="color:#981a1a">=</span> <span style="color:#008855">Integer</span>.<span style="color:#000000">toBinaryString</span>(<span style="color:#000000">num</span>);
        <span style="color:#008855">String</span> <span style="color:#000000">hexString</span> <span style="color:#981a1a">=</span> <span style="color:#008855">Integer</span>.<span style="color:#000000">toHexString</span>(<span style="color:#000000">num</span>);
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Binary: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">binaryString</span>); <span style="color:#aa5500">// 输出:Binary: 101010</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Hex: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">hexString</span>);       <span style="color:#aa5500">// 输出:Hex: 2a</span>
    }
}</span></span>

16.4 使用包装类进行数值比较

当你需要将基本数据类型封装成对象并进行比较时,可以使用包装类。例如,你可以使用Integer类的compareTo()方法来比较两个整数的大小。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Main</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#008855">Integer</span> <span style="color:#000000">num1</span> <span style="color:#981a1a">=</span> <span style="color:#116644">42</span>;
        <span style="color:#008855">Integer</span> <span style="color:#000000">num2</span> <span style="color:#981a1a">=</span> <span style="color:#116644">24</span>;
​
        <span style="color:#008855">int</span> <span style="color:#000000">comparisonResult</span> <span style="color:#981a1a">=</span> <span style="color:#000000">num1</span>.<span style="color:#000000">compareTo</span>(<span style="color:#000000">num2</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Comparison result: "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">comparisonResult</span>); <span style="color:#aa5500">// 输出:Comparison result: 1</span>
    }
}</span></span>

17 关键字:static

回顾类中的实例变量(即非static的成员变量)

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">Circle</span>{
    <span style="color:#770088">private</span> <span style="color:#008855">double</span> <span style="color:#000000">radius</span>;
    <span style="color:#770088">public</span> <span style="color:#000000">Circle</span>(<span style="color:#008855">double</span> <span style="color:#000000">radius</span>){
        <span style="color:#770088">this</span>.<span style="color:#000000">radius</span><span style="color:#981a1a">=</span><span style="color:#000000">radius</span>;
    }
    <span style="color:#770088">public</span> <span style="color:#008855">double</span> <span style="color:#000000">findArea</span>(){
        <span style="color:#770088">return</span> <span style="color:#000000">Math</span>.<span style="color:#000000">PI</span><span style="color:#981a1a">*</span><span style="color:#000000">radius</span><span style="color:#981a1a">*</span><span style="color:#000000">radius</span>;
    }
}</span></span>

创建两个Circle对象:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">Circle</span> <span style="color:#000000">c1</span><span style="color:#981a1a">=</span><span style="color:#770088">new</span> <span style="color:#000000">Circle</span>(<span style="color:#116644">2.0</span>);  <span style="color:#aa5500">//c1.radius=2.0</span>
<span style="color:#000000">Circle</span> <span style="color:#000000">c2</span><span style="color:#981a1a">=</span><span style="color:#770088">new</span> <span style="color:#000000">Circle</span>(<span style="color:#116644">3.0</span>);  <span style="color:#aa5500">//c2.radius=3.0</span></span></span>

Circle类中的变量radius是一个实例变量(instance variable),它属于类的每一个对象,c1中的radius变化不会影响c2的radius,反之亦然。

如果想让一个成员变量被类的所有实例所共享,就用static修饰即可,称为类变量(或类属性)!

17.1 类属性、类方法的设计思想

当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。例如,所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。

此外,在类中声明的实例方法,在类的外面必须要先创建对象,才能调用。但是有些方法的调用者和当前类的对象无关,这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。

这里的类变量、类方法,只需要使用static修饰即可。所以也称为静态变量、静态方法。

17.2 static关键字

  • 使用范围:

    • 在Java类中,可用static修饰属性、方法、代码块、内部类

  • 被修饰后的成员具备以下特点:

    • 随着类的加载而加载

    • 优先于对象存在

    • 修饰的成员,被所有对象所共享

    • 访问权限允许时,可不创建对象,直接被类调用

17.3 静态变量

17.3.1 语法格式

使用static修饰的成员变量就是静态变量(或类变量、类属性)

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#000000">修饰符</span>] <span style="color:#770088">class</span> <span style="color:#0000ff">类</span>{
    [<span style="color:#000000">其他修饰符</span>] <span style="color:#770088">static</span> <span style="color:#000000">数据类型</span> <span style="color:#000000">变量名</span>;
}</span></span>

17.3.2 静态变量的特点

  • 静态变量的默认值规则和实例变量一样。

  • 静态变量值是所有对象共享。

  • 静态变量在本类中,可以在任意方法、代码块、构造器中直接使用。

  • 如果权限修饰符允许,在其他类中可以通过“类名.静态变量”直接访问,也可以通过“对象.静态变量”的方式访问(但是更推荐使用类名.静态变量的方式)。

  • 静态变量的get/set方法也静态的,当局部变量与静态变量重名时,使用“类名.静态变量”进行区分。

17.3.3 举例

举例1:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">Chinese</span>{
    <span style="color:#aa5500">//实例变量</span>
    <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
    <span style="color:#008855">int</span> <span style="color:#000000">age</span>;
    <span style="color:#aa5500">//类变量</span>
    <span style="color:#770088">static</span> <span style="color:#008855">String</span> <span style="color:#000000">nation</span>;<span style="color:#aa5500">//国籍</span>
​
    <span style="color:#770088">public</span> <span style="color:#000000">Chinese</span>() {
    }
​
    <span style="color:#770088">public</span> <span style="color:#000000">Chinese</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>, <span style="color:#008855">int</span> <span style="color:#000000">age</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
        <span style="color:#770088">this</span>.<span style="color:#000000">age</span> <span style="color:#981a1a">=</span> <span style="color:#000000">age</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">toString</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"Chinese{"</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">"name='"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">'\''</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">", age="</span> <span style="color:#981a1a">+</span> <span style="color:#000000">age</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">", nation='"</span> <span style="color:#981a1a">+</span> <span style="color:#000000">nation</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">'\''</span> <span style="color:#981a1a">+</span>
                <span style="color:#aa1111">'}'</span>;
    }
}
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">StaticTest</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Chinese</span> <span style="color:#000000">c1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Chinese</span>(<span style="color:#aa1111">"康师傅"</span>,<span style="color:#116644">36</span>);
        <span style="color:#000000">c1</span>.<span style="color:#000000">nation</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"中华人民共和国"</span>;
​
        <span style="color:#000000">Chinese</span> <span style="color:#000000">c2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Chinese</span>(<span style="color:#aa1111">"老干妈"</span>,<span style="color:#116644">66</span>);
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">c1</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">c2</span>);
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">Chinese</span>.<span style="color:#000000">nation</span>);
    }
}</span></span>

举例2:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Employee</span> {
    <span style="color:#770088">private</span> <span style="color:#770088">static</span> <span style="color:#008855">int</span> <span style="color:#000000">total</span>;<span style="color:#aa5500">//这里私有化,在类的外面必须使用get/set方法的方式来访问静态变量</span>
    <span style="color:#770088">static</span> <span style="color:#008855">String</span> <span style="color:#000000">company</span>; <span style="color:#aa5500">//这里缺省权限修饰符,是为了方便类外以“类名.静态变量”的方式访问</span>
    <span style="color:#770088">private</span> <span style="color:#008855">int</span> <span style="color:#000000">id</span>;
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">name</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Employee</span>() {
        <span style="color:#000000">total</span><span style="color:#981a1a">++</span>;
        <span style="color:#000000">id</span> <span style="color:#981a1a">=</span> <span style="color:#000000">total</span>;<span style="color:#aa5500">//这里使用total静态变量的值为id属性赋值</span>
    }
​
    <span style="color:#770088">public</span> <span style="color:#000000">Employee</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>();
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setId</span>(<span style="color:#008855">int</span> <span style="color:#000000">id</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">id</span> <span style="color:#981a1a">=</span> <span style="color:#000000">id</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">getId</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">id</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getName</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">setName</span>(<span style="color:#008855">String</span> <span style="color:#000000">name</span>) {
        <span style="color:#770088">this</span>.<span style="color:#000000">name</span> <span style="color:#981a1a">=</span> <span style="color:#000000">name</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">int</span> <span style="color:#000000">getTotal</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">total</span>;
    }
​
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">setTotal</span>(<span style="color:#008855">int</span> <span style="color:#000000">total</span>) {
        <span style="color:#000000">Employee</span>.<span style="color:#000000">total</span> <span style="color:#981a1a">=</span> <span style="color:#000000">total</span>;
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">toString</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"Employee{company = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">company</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">",id = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">id</span> <span style="color:#981a1a">+</span> <span style="color:#aa1111">" ,name="</span> <span style="color:#981a1a">+</span> <span style="color:#000000">name</span> <span style="color:#981a1a">+</span><span style="color:#aa1111">"}"</span>;
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestStaticVariable</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">//静态变量total的默认值是0</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Employee.total = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">Employee</span>.<span style="color:#000000">getTotal</span>());
​
        <span style="color:#000000">Employee</span> <span style="color:#000000">e1</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Employee</span>(<span style="color:#aa1111">"张三"</span>);
        <span style="color:#000000">Employee</span> <span style="color:#000000">e2</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Employee</span>(<span style="color:#aa1111">"李四"</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">e1</span>);<span style="color:#aa5500">//静态变量company的默认值是null</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">e2</span>);<span style="color:#aa5500">//静态变量company的默认值是null</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Employee.total = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">Employee</span>.<span style="color:#000000">getTotal</span>());<span style="color:#aa5500">//静态变量total值是2</span>
​
        <span style="color:#000000">Employee</span>.<span style="color:#000000">company</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"尚硅谷"</span>;
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">e1</span>);<span style="color:#aa5500">//静态变量company的值是尚硅谷</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">e2</span>);<span style="color:#aa5500">//静态变量company的值是尚硅谷</span>
​
        <span style="color:#aa5500">//只要权限修饰符允许,虽然不推荐,但是也可以通过“对象.静态变量”的形式来访问</span>
        <span style="color:#000000">e1</span>.<span style="color:#000000">company</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"超级尚硅谷"</span>;
​
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">e1</span>);<span style="color:#aa5500">//静态变量company的值是超级尚硅谷</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">e2</span>);<span style="color:#aa5500">//静态变量company的值是超级尚硅谷</span>
    }
}</span></span>

17.4 静态方法

17.4.1 语法格式

用static修饰的成员方法就是静态方法。

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#000000">修饰符</span>] <span style="color:#770088">class</span> <span style="color:#0000ff">类</span>{
    [<span style="color:#000000">其他修饰符</span>] <span style="color:#770088">static</span> <span style="color:#000000">返回值类型</span> <span style="color:#000000">方法名</span>(<span style="color:#000000">形参列表</span>){
        <span style="color:#000000">方法体</span>
    }
}</span></span>

17.4.2 静态方法的特点

  • 静态方法在本类的任意方法、代码块、构造器中都可以直接被调用。

  • 只要权限修饰符允许,静态方法在其他类中可以通过“类名.静态方法“的方式调用。也可以通过”对象.静态方法“的方式调用(但是更推荐使用类名.静态方法的方式)。

  • 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构。

  • 静态方法可以被子类继承,但不能被子类重写。

  • 静态方法的调用都只看编译时类型。

  • 因为不需要实例就可以访问static方法,因此static方法内部不能有this,也不能有super。如果有重名问题,使用“类名.”进行区别。

17.4.3 举例

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">keyword</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Father</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Father.method"</span>);
    }
​
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">fun</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Father.fun"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">keyword</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Son</span> <span style="color:#770088">extends</span> <span style="color:#000000">Father</span>{
<span style="color:#aa5500">//    @Override //尝试重写静态方法,加上@Override编译报错,去掉Override不报错,但是也不是重写</span>
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">fun</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Son.fun"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">keyword</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestStaticMethod</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Father</span>.<span style="color:#000000">method</span>();
        <span style="color:#000000">Son</span>.<span style="color:#000000">method</span>();<span style="color:#aa5500">//继承静态方法</span>
​
        <span style="color:#000000">Father</span> <span style="color:#000000">f</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Son</span>();
        <span style="color:#000000">f</span>.<span style="color:#000000">method</span>();<span style="color:#aa5500">//执行Father类中的method</span>
    }
}</span></span>

18 final关键字

18.1 final的意义

final:最终的,不可更改的

18.2 final的使用

18.2.1 final修饰类

表示这个类不能被继承,没有子类。提高安全性,提高程序的可读性。

例如:String类、System类、StringBuffer类

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">final</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Eunuch</span>{<span style="color:#aa5500">//太监类</span>
    
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Son</span> <span style="color:#770088">extends</span> <span style="color:#000000">Eunuch</span>{<span style="color:#aa5500">//错误</span>
    
}</span></span>

18.2.2 final修饰方法

表示这个方法不能被子类重写。

例如:Object类中的getClass()

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">Father</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">final</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"father"</span>);
    }
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Son</span> <span style="color:#770088">extends</span> <span style="color:#000000">Father</span>{
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(){<span style="color:#aa5500">//错误</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"son"</span>);
    }
}</span></span>

18.2.3 final修饰变量

final修饰某个变量(成员变量或局部变量),一旦赋值,它的值就不能被修改,即常量,常量名建议使用大写字母。

例如:final double MY_PI = 3.14;

如果某个成员变量用final修饰后,没有set方法,并且必须初始化(可以显式赋值、或在初始化块赋值、实例变量还可以在构造器中赋值)

  • 修饰成员变量

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">final</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Test</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">int</span> <span style="color:#000000">totalNumber</span> <span style="color:#981a1a">=</span> <span style="color:#116644">5</span>;
    <span style="color:#770088">public</span> <span style="color:#770088">final</span> <span style="color:#008855">int</span> <span style="color:#000000">ID</span>;
​
    <span style="color:#770088">public</span> <span style="color:#000000">Test</span>() {
        <span style="color:#000000">ID</span> <span style="color:#981a1a">=</span> <span style="color:#981a1a">++</span><span style="color:#000000">totalNumber</span>; <span style="color:#aa5500">// 可在构造器中给final修饰的“变量”赋值</span>
    }
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Test</span> <span style="color:#000000">t</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Test</span>();
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">t</span>.<span style="color:#000000">ID</span>);
    }
}
​</span></span>
  • 修饰局部变量:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestFinal</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>){
        <span style="color:#770088">final</span> <span style="color:#008855">int</span> <span style="color:#000000">MIN_SCORE</span> ;
        <span style="color:#000000">MIN_SCORE</span> <span style="color:#981a1a">=</span> <span style="color:#116644">0</span>;
        <span style="color:#770088">final</span> <span style="color:#008855">int</span> <span style="color:#000000">MAX_SCORE</span> <span style="color:#981a1a">=</span> <span style="color:#116644">100</span>;
        <span style="color:#000000">MAX_SCORE</span> <span style="color:#981a1a">=</span> <span style="color:#116644">200</span>; <span style="color:#aa5500">//非法</span>
    }
}</span></span>
  • 错误演示:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">class</span> <span style="color:#0000ff">A</span> {
    <span style="color:#770088">private</span> <span style="color:#770088">final</span> <span style="color:#008855">String</span> <span style="color:#000000">INFO</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"baidu"</span>;  <span style="color:#aa5500">//声明常量</span>
​
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">print</span>() {
        <span style="color:#aa5500">//The final field A.INFO cannot be  assigned</span>
        <span style="color:#aa5500">//INFO = "百度"; </span>
    }
}
​</span></span>

19 抽象类

19.1 由来

举例1:

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

举例2:

我们声明一些几何图形类:圆、矩形、三角形类等,发现这些类都有共同特征:求面积、求周长。那么这些共同特征应该抽取到一个共同父类:几何图形类中。但是这些方法在父类中又无法给出具体的实现,而是应该交给子类各自具体实现。那么父类在声明这些方法时,就只有方法签名,没有方法体,我们把没有方法体的方法称为抽象方法。Java语法规定,包含抽象方法的类必须是抽象类

19.2 语法格式

  • 抽象类:被abstract修饰的类。

  • 抽象方法:被abstract修饰没有方法体的方法。

抽象类的语法格式

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#000000">权限修饰符</span>] <span style="color:#770088">abstract</span> <span style="color:#770088">class</span> <span style="color:#0000ff">类名</span>{
    
}
[<span style="color:#000000">权限修饰符</span>] <span style="color:#770088">abstract</span> <span style="color:#770088">class</span> <span style="color:#0000ff">类名</span> <span style="color:#770088">extends</span> <span style="color:#000000">父类</span>{
    
}</span></span>

抽象方法的语法格式

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#000000">其他修饰符</span>] <span style="color:#770088">abstract</span> <span style="color:#000000">返回值类型</span> <span style="color:#0000ff">方法名</span>([<span style="color:#000000">形参列表</span>]);</span></span>

代码举例:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">abstract</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Animal</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">abstract</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span>();
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Cat</span> <span style="color:#770088">extends</span> <span style="color:#000000">Animal</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">eat</span> (){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"小猫吃鱼和猫粮"</span>); 
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">CatTest</span> {
     <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">// 创建子类对象</span>
        <span style="color:#000000">Cat</span> <span style="color:#000000">c</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Cat</span>(); 
       
        <span style="color:#aa5500">// 调用eat方法</span>
        <span style="color:#000000">c</span>.<span style="color:#000000">eat</span>();
    }
}</span></span>

此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法

19.3 使用说明

  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

    理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

    抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。

  2. 抽象类中,也有构造方法,是供子类创建对象时,初始化父类成员变量使用的。

    理解:子类的构造方法中,有默认的super()或手动的super(实参列表),需要访问父类构造方法。

  3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

    理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。

  4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

    理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

20 接口

20.1 概述

接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的is-a关系,而接口实现则是 "能不能"的has-a关系。

接口的本质是契约、标准、规范,就像我们的法律一样。制定好后大家都要遵守。

20.2 定义格式

接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。

引用数据类型:数组,类,枚举,接口,注解。

20.2.1 接口的声明格式

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#000000">修饰符</span>] <span style="color:#770088">interface</span> <span style="color:#0000ff">接口名</span>{
    <span style="color:#aa5500">//接口的成员列表:</span>
    <span style="color:#aa5500">// 公共的静态常量</span>
    <span style="color:#aa5500">// 公共的抽象方法</span>
    
    <span style="color:#aa5500">// 公共的默认方法(JDK1.8以上)</span>
    <span style="color:#aa5500">// 公共的静态方法(JDK1.8以上)</span>
    <span style="color:#aa5500">// 私有方法(JDK1.9以上)</span>
}</span></span>

示例代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">USB3</span>{
    <span style="color:#aa5500">//静态常量</span>
    <span style="color:#008855">long</span> <span style="color:#000000">MAX_SPEED</span> <span style="color:#981a1a">=</span> <span style="color:#116644">500</span><span style="color:#981a1a">*</span><span style="color:#116644">1024</span><span style="color:#981a1a">*</span><span style="color:#116644">1024</span>;<span style="color:#aa5500">//500MB/s</span>
​
    <span style="color:#aa5500">//抽象方法</span>
    <span style="color:#008855">void</span> <span style="color:#000000">in</span>();
    <span style="color:#008855">void</span> <span style="color:#000000">out</span>();
​
    <span style="color:#aa5500">//默认方法</span>
    <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"开始"</span>);
    }
    <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"结束"</span>);
    }
​
    <span style="color:#aa5500">//静态方法</span>
    <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">show</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"USB 3.0可以同步全速地进行读写操作"</span>);
    }
}</span></span>

20.3.2 接口的成员说明

在JDK8.0 之前,接口中只允许出现:

(1)公共的静态的常量:其中public static final可以省略

(2)公共的抽象的方法:其中public abstract可以省略

理解:接口是从多个相似类中抽象出来的规范,不需要提供具体实现

在JDK8.0 时,接口中允许声明默认方法静态方法

(3)公共的默认的方法:其中public 可以省略,建议保留,但是default不能省略

(4)公共的静态的方法:其中public 可以省略,建议保留,但是static不能省略

在JDK9.0 时,接口又增加了:

(5)私有方法

除此之外,接口中没有构造器,没有初始化块,因为接口中没有成员变量需要动态初始化。

20.3 接口的使用规则

20.3.1 类实现接口(implements)

接口不能创建对象,但是可以被类实现(implements ,类似于被继承)。

类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements关键字。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">【修饰符】</span> <span style="color:#770088">class</span> <span style="color:#0000ff">实现类</span>  <span style="color:#770088">implements</span> <span style="color:#000000">接口</span>{
    <span style="color:#aa5500">// 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写</span>
    <span style="color:#aa5500">// 重写接口中默认方法【可选】</span>
}
​
<span style="color:#000000">【修饰符】</span> <span style="color:#770088">class</span> <span style="color:#0000ff">实现类</span> <span style="color:#770088">extends</span> <span style="color:#000000">父类</span> <span style="color:#770088">implements</span> <span style="color:#000000">接口</span>{
    <span style="color:#aa5500">// 重写接口中抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写</span>
    <span style="color:#aa5500">// 重写接口中默认方法【可选】</span>
}</span></span>

注意:

  1. 如果接口的实现类是非抽象类,那么必须重写接口中所有抽象方法

  2. 默认方法可以选择保留,也可以重写。

    重写时,default单词就不要再写了,它只用于在接口中表示默认方法,到类中就没有默认方法的概念了

  3. 接口中的静态方法不能被继承也不能被重写

举例:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">interface</span> <span style="color:#0000ff">USB</span>{      <span style="color:#aa5500">// </span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>() ;
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>() ;    
}
<span style="color:#770088">class</span> <span style="color:#0000ff">Computer</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">show</span>(<span style="color:#000000">USB</span> <span style="color:#000000">usb</span>){   
        <span style="color:#000000">usb</span>.<span style="color:#000000">start</span>() ;
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"=========== USB 设备工作 ========"</span>) ;
        <span style="color:#000000">usb</span>.<span style="color:#000000">stop</span>() ;
    }
};
<span style="color:#770088">class</span> <span style="color:#0000ff">Flash</span> <span style="color:#770088">implements</span> <span style="color:#000000">USB</span>{
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>(){    <span style="color:#aa5500">// 重写方法</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"U盘开始工作。"</span>) ;
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>(){     <span style="color:#aa5500">// 重写方法</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"U盘停止工作。"</span>) ;
    }
};
<span style="color:#770088">class</span> <span style="color:#0000ff">Print</span> <span style="color:#770088">implements</span> <span style="color:#000000">USB</span>{
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>(){    <span style="color:#aa5500">// 重写方法</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"打印机开始工作。"</span>) ;
    }
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>(){     <span style="color:#aa5500">// 重写方法</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"打印机停止工作。"</span>) ;
    }
};
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">InterfaceDemo</span>{
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span> <span style="color:#000000">args</span>[]){
        <span style="color:#000000">Computer</span>.<span style="color:#000000">show</span>(<span style="color:#770088">new</span> <span style="color:#000000">Flash</span>()) ;
        <span style="color:#000000">Computer</span>.<span style="color:#000000">show</span>(<span style="color:#770088">new</span> <span style="color:#000000">Print</span>()) ;
​
        <span style="color:#000000">c</span>.<span style="color:#000000">show</span>(<span style="color:#770088">new</span> <span style="color:#000000">USB</span>(){
            <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>(){
                <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"移动硬盘开始运行"</span>);
            }
            <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>(){
                <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"移动硬盘停止运行"</span>);
            }
        });
    }
};</span></span>

20.3.2 接口的多实现(implements)

之前学过,在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。

实现格式:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">【修饰符】</span> <span style="color:#770088">class</span> <span style="color:#0000ff">实现类</span>  <span style="color:#770088">implements</span> <span style="color:#000000">接口1,接口2,接口3。。。</span>{
    <span style="color:#aa5500">// 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写</span>
    <span style="color:#aa5500">// 重写接口中默认方法【可选】</span>
}
​
<span style="color:#000000">【修饰符】</span> <span style="color:#770088">class</span> <span style="color:#0000ff">实现类</span> <span style="color:#770088">extends</span> <span style="color:#000000">父类</span> <span style="color:#770088">implements</span> <span style="color:#000000">接口1,接口2,接口3。。。</span>{
    <span style="color:#aa5500">// 重写接口中所有抽象方法【必须】,当然如果实现类是抽象类,那么可以不重写</span>
    <span style="color:#aa5500">// 重写接口中默认方法【可选】</span>
}</span></span>

接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次

定义多个接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">A</span> {
    <span style="color:#008855">void</span> <span style="color:#000000">showA</span>();
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">B</span> {
    <span style="color:#008855">void</span> <span style="color:#000000">showB</span>();
}</span></span>

定义实现类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">C</span> <span style="color:#770088">implements</span> <span style="color:#000000">A</span>,<span style="color:#000000">B</span> {
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">showA</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"showA"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">showB</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"showB"</span>);
    }
}
​</span></span>

测试类

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestC</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">C</span> <span style="color:#000000">c</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">C</span>();
        <span style="color:#000000">c</span>.<span style="color:#000000">showA</span>();
        <span style="color:#000000">c</span>.<span style="color:#000000">showB</span>();
    }
}</span></span>

3、接口的多继承(extends)

一个接口能继承另一个或者多个接口,接口的继承也使用 extends 关键字,子接口继承父接口的方法。

定义父接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">Chargeable</span> {
    <span style="color:#008855">void</span> <span style="color:#000000">charge</span>();
    <span style="color:#008855">void</span> <span style="color:#000000">in</span>();
    <span style="color:#008855">void</span> <span style="color:#000000">out</span>();
}</span></span>

定义子接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">UsbC</span> <span style="color:#770088">extends</span> <span style="color:#000000">Chargeable</span>,<span style="color:#000000">USB3</span> {
    <span style="color:#008855">void</span> <span style="color:#000000">reverse</span>();
}</span></span>

定义子接口的实现类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TypeCConverter</span> <span style="color:#770088">implements</span> <span style="color:#000000">UsbC</span> {
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">reverse</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"正反面都支持"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">charge</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"可充电"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">in</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"接收数据"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">out</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"输出数据"</span>);
    }
}</span></span>

所有父接口的抽象方法都有重写。

方法签名相同的抽象方法只需要实现一次。

4、接口与实现类对象构成多态引用

实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是你new的实现类对象实现的方法体。

接口的不同实现类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Mouse</span> <span style="color:#770088">implements</span> <span style="color:#000000">USB3</span> {
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">out</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"发送脉冲信号"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">in</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"不接收信号"</span>);
    }
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">KeyBoard</span> <span style="color:#770088">implements</span> <span style="color:#000000">USB3</span>{
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">in</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"不接收信号"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">out</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"发送按键信号"</span>);
    }
}
​</span></span>

测试类

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestComputer</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Computer</span> <span style="color:#000000">computer</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Computer</span>();
        <span style="color:#000000">USB3</span> <span style="color:#000000">usb</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Mouse</span>();
        <span style="color:#000000">computer</span>.<span style="color:#000000">setUsb</span>(<span style="color:#000000">usb</span>);
        <span style="color:#000000">usb</span>.<span style="color:#000000">start</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">out</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">in</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">stop</span>();
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"--------------------------"</span>);
​
        <span style="color:#000000">usb</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">KeyBoard</span>();
        <span style="color:#000000">computer</span>.<span style="color:#000000">setUsb</span>(<span style="color:#000000">usb</span>);
        <span style="color:#000000">usb</span>.<span style="color:#000000">start</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">out</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">in</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">stop</span>();
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"--------------------------"</span>);
​
        <span style="color:#000000">usb</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">MobileHDD</span>();
        <span style="color:#000000">computer</span>.<span style="color:#000000">setUsb</span>(<span style="color:#000000">usb</span>);
        <span style="color:#000000">usb</span>.<span style="color:#000000">start</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">out</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">in</span>();
        <span style="color:#000000">usb</span>.<span style="color:#000000">stop</span>();
    }
}</span></span>

5、使用接口的静态成员

接口不能直接创建对象,但是可以通过接口名直接调用接口的静态方法和静态常量。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestUSB3</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">//通过“接口名.”调用接口的静态方法 (JDK8.0才能开始使用)</span>
        <span style="color:#000000">USB3</span>.<span style="color:#000000">show</span>();
        <span style="color:#aa5500">//通过“接口名.”直接使用接口的静态常量</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">USB3</span>.<span style="color:#000000">MAX_SPEED</span>);
    }
}</span></span>

6、使用接口的非静态方法

  • 对于接口的静态方法,直接使用“接口名.”进行调用即可

    • 也只能使用“接口名."进行调用,不能通过实现类的对象进行调用

  • 对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用

    • 接口不能直接创建对象,只能创建实现类的对象

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestMobileHDD</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#aa5500">//创建实现类对象</span>
        <span style="color:#000000">MobileHDD</span> <span style="color:#000000">b</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">MobileHDD</span>();
​
        <span style="color:#aa5500">//通过实现类对象调用重写的抽象方法,以及接口的默认方法,如果实现类重写了就执行重写的默认方法,如果没有重写,就执行接口中的默认方法</span>
        <span style="color:#000000">b</span>.<span style="color:#000000">start</span>();
        <span style="color:#000000">b</span>.<span style="color:#000000">in</span>();
        <span style="color:#000000">b</span>.<span style="color:#000000">stop</span>();
​
        <span style="color:#aa5500">//通过接口名调用接口的静态方法</span>
<span style="color:#aa5500">//        MobileHDD.show();</span>
<span style="color:#aa5500">//        b.show();</span>
        <span style="color:#000000">Usb3</span>.<span style="color:#000000">show</span>();
    }
}</span></span>

20.4 JDK8中相关冲突问题

20.4.1 默认方法冲突问题

(1)类优先原则

当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。代码如下:

定义接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">Friend</span> {
    <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">date</span>(){<span style="color:#aa5500">//约会</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"吃喝玩乐"</span>);
    }
}</span></span>

定义父类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Father</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">date</span>(){<span style="color:#aa5500">//约会</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"爸爸约吃饭"</span>);
    }
}</span></span>

定义子类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Son</span> <span style="color:#770088">extends</span> <span style="color:#000000">Father</span> <span style="color:#770088">implements</span> <span style="color:#000000">Friend</span> {
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">date</span>() {
        <span style="color:#aa5500">//(1)不重写默认保留父类的</span>
        <span style="color:#aa5500">//(2)调用父类被重写的</span>
<span style="color:#aa5500">//        super.date();</span>
        <span style="color:#aa5500">//(3)保留父接口的</span>
<span style="color:#aa5500">//        Friend.super.date();</span>
        <span style="color:#aa5500">//(4)完全重写</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"跟康师傅学Java"</span>);
    }
}</span></span>

定义测试类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestSon</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Son</span> <span style="color:#000000">s</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Son</span>();
        <span style="color:#000000">s</span>.<span style="color:#000000">date</span>();
    }
}</span></span>

(2)接口冲突(左右为难)

  • 当一个类同时实现了多个父接口,而多个父接口中包含方法签名相同的默认方法时,怎么办呢?

无论你多难抉择,最终都是要做出选择的。

声明接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">BoyFriend</span> {
    <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">date</span>(){<span style="color:#aa5500">//约会</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"神秘约会"</span>);
    }
}</span></span>

选择保留其中一个,通过“接口名.super.方法名"的方法选择保留哪个接口的默认方法。

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">Girl</span> <span style="color:#770088">implements</span> <span style="color:#000000">Friend</span>,<span style="color:#000000">BoyFriend</span>{
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">date</span>() {
        <span style="color:#aa5500">//(1)保留其中一个父接口的</span>
<span style="color:#aa5500">//        Friend.super.date();</span>
<span style="color:#aa5500">//        BoyFriend.super.date();</span>
        <span style="color:#aa5500">//(2)完全重写</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"跟康师傅学Java"</span>);
    }
​
}</span></span>

测试类

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">TestGirl</span> {
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">main</span>(<span style="color:#008855">String</span>[] <span style="color:#000000">args</span>) {
        <span style="color:#000000">Girl</span> <span style="color:#000000">girl</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">Girl</span>();
        <span style="color:#000000">girl</span>.<span style="color:#000000">date</span>();
    }
}</span></span>
  • 当一个子接口同时继承了多个接口,而多个父接口中包含方法签名相同的默认方法时,怎么办呢?

另一个父接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">USB2</span> {
    <span style="color:#aa5500">//静态常量</span>
    <span style="color:#008855">long</span> <span style="color:#000000">MAX_SPEED</span> <span style="color:#981a1a">=</span> <span style="color:#116644">60</span><span style="color:#981a1a">*</span><span style="color:#116644">1024</span><span style="color:#981a1a">*</span><span style="color:#116644">1024</span>;<span style="color:#aa5500">//60MB/s</span>
​
    <span style="color:#aa5500">//抽象方法</span>
    <span style="color:#008855">void</span> <span style="color:#000000">in</span>();
    <span style="color:#008855">void</span> <span style="color:#000000">out</span>();
​
    <span style="color:#aa5500">//默认方法</span>
    <span style="color:#770088">public</span> <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"开始"</span>);
    }
    <span style="color:#770088">public</span> <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"结束"</span>);
    }
​
    <span style="color:#aa5500">//静态方法</span>
    <span style="color:#770088">public</span> <span style="color:#770088">static</span> <span style="color:#008855">void</span> <span style="color:#000000">show</span>(){
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"USB 2.0可以高速地进行读写操作"</span>);
    }
}</span></span>

子接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">USB</span> <span style="color:#770088">extends</span> <span style="color:#000000">USB2</span>,<span style="color:#000000">USB3</span> {
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">start</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Usb.start"</span>);
    }
​
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">default</span> <span style="color:#008855">void</span> <span style="color:#000000">stop</span>() {
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"Usb.stop"</span>);
    }
}
​</span></span>

小贴士:

子接口重写默认方法时,default关键字可以保留。

子类重写默认方法时,default关键字不可以保留。

20.4.2 常量冲突问题

  • 当子类继承父类又实现父接口,而父类中存在与父接口常量同名的成员变量,并且该成员变量名在子类中仍然可见。

  • 当子类同时实现多个接口,而多个接口存在相同同名常量。

此时在子类中想要引用父类或父接口的同名的常量或成员变量时,就会有冲突问题。

父类和父接口:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SuperClass</span> {
    <span style="color:#008855">int</span> <span style="color:#000000">x</span> <span style="color:#981a1a">=</span> <span style="color:#116644">1</span>;
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">SuperInterface</span> {
    <span style="color:#008855">int</span> <span style="color:#000000">x</span> <span style="color:#981a1a">=</span> <span style="color:#116644">2</span>;
    <span style="color:#008855">int</span> <span style="color:#000000">y</span> <span style="color:#981a1a">=</span> <span style="color:#116644">2</span>;
}</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">MotherInterface</span> {
    <span style="color:#008855">int</span> <span style="color:#000000">x</span> <span style="color:#981a1a">=</span> <span style="color:#116644">3</span>;
}</span></span>

子类:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">atguigu</span>.<span style="color:#000000">interfacetype</span>;
​
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">SubClass</span> <span style="color:#770088">extends</span> <span style="color:#000000">SuperClass</span> <span style="color:#770088">implements</span> <span style="color:#000000">SuperInterface</span>,<span style="color:#000000">MotherInterface</span> {
    <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">method</span>(){
<span style="color:#aa5500">//        System.out.println("x = " + x);//模糊不清</span>
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"super.x = "</span> <span style="color:#981a1a">+</span> <span style="color:#770088">super</span>.<span style="color:#000000">x</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"SuperInterface.x = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">SuperInterface</span>.<span style="color:#000000">x</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"MotherInterface.x = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">MotherInterface</span>.<span style="color:#000000">x</span>);
        <span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#aa1111">"y = "</span> <span style="color:#981a1a">+</span> <span style="color:#000000">y</span>);<span style="color:#aa5500">//没有重名问题,可以直接访问</span>
    }
}</span></span>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/584902.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最优二叉搜索树

一、二叉搜索树&#xff08;二叉查找树&#xff09; 所有根节点大于左子树的节点&#xff0c;小于右子树的节点的二叉树 满足以下性质&#xff1a; 1.如果左子树不为空&#xff0c;则左子树上的所有节点都小于根节点 2.如果右子树不为空&#xff0c;则右子树上的所有节点都大于…

Web-SpringBootWeb

创建项目 后面因为报错&#xff0c;所以我把jdk修改成22&#xff0c;仅供参考。 定义类&#xff0c;创建方法 package com.start.springbootstart.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotati…

实验8 NAT配置

实验8 NAT配置 一、 原理描述二、 实验目的三、 实验内容1.实验场景2.实验要求 四、 实验配置五、 实验步骤2.静态NAT配置3.NAT Outbound配置4.NAT Easy-IP配置 一、 原理描述 2019年11月26日&#xff0c;全球43亿个IPv4地址正式耗尽&#xff0c;这意味着没有更多的IPv4地址可…

基于SSM的“航空机票预订系统”的设计与实现(源码+数据库+文档+PPT)

基于SSM的“航空机票预订系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SSM 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页 公告管理 用户注册 留言评论 会员管理 航班管理 订…

uniApp+Vue3+vite+Element UI或者Element Plus开发学习,使用vite构建管理项目,HBuilderX做为开发者工具

我们通常给小程序或者app开发后台时&#xff0c;不可避免的要用到可视化的数据管理后台&#xff0c;而vue和Element是我们目前比较主流的开发管理后台的主流搭配。所以今天石头哥就带大家来一起学习下vue3和Element plus的开发。 准备工作 1&#xff0c;下载HBuilderX 开发者…

IDEA插件-通义灵码 VS ChatGPT-EasyCode

智能编码助手新时代&#xff1a;通义灵码 vs ChatGPT-EasyCode 随着人工智能技术的飞速发展&#xff0c;智能编码助手逐渐成为程序员的必备工具。它们可以帮助程序员提高编码效率&#xff0c;降低代码缺陷率&#xff0c;并解放创造力。 目前市场上涌现出了众多智能编码助手&a…

npm install 卡住不动不执行解决方法

npm install 卡住不动不执行解决方法&#xff0c;先是想到的切淘宝镜像&#xff0c;于是》》》 走淘宝镜像&#xff0c;结果淘宝镜像挂了,于是》》》》》 切成这个 https://registry.npmmirror.com/ 大功告成&#xff01;

访问公共盘时提示:你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问。这些策略可帮助保护你的电脑免受网络上不安全设备或恶意设备的威胁。

原因&#xff1a;未启动启用策略&#xff1a;不安全的来宾登录 办法&#xff1a; 1&#xff0c;WindowsR键&#xff0c;打开运行&#xff0c;输入gpedit.msc&#xff0c;打开本地组策略编辑器&#xff1b;2&#xff0c;计算机配置>管理模板>网络>Lanman 工作站>启…

KUKA机器人如何给IO信号或寄存器添加中文注释信息?

KUKA机器人如何给IO信号或寄存器添加中文注释信息? 如下图所示,首先,我们需要登录专家以上用户权限(默认密码KUKA), 如下图所示,点击“投入运行”—“网络配置”, 如下图所示,此时机器人的IP地址为192.168.1.10, 如下图所示,用一根网线连接机器人控制柜到笔记…

第1章 手写WebServer

1.1 Web原理 1.1.1 Web概述 Web是指互联网上的万维网&#xff08;World Wide Web&#xff09;&#xff0c;是一个由超文本、超链接和多媒体内容组成的信息空间。Web的基础技术是HTTP协议、URL、HTML、CSS和JavaScript等。Web被广泛应用于信息检索、在线购物、社交媒体、在线游…

kettle将excel表数据导入到oracle表中

上一篇已经介绍过kettle8.2的安装。 之前一直使用的sqlldr导入外部表&#xff0c;导入比较耗时&#xff0c;这次想使用一下kettle试试。 1.新建转换 2.新建输入 3.新建输出 4.转换新建完成 5.配置输入 加载表格文件 配置工作表 加载字段 6.配置输出 测试数据库连接 这…

指标完成情况对比查询sql

指标完成情况对比查询sql 1. 需求 2. SQL select--部门dept.name as bm,--年度指标任务-新签&#xff08;万元&#xff09;ndzbwh.nxqndzbrw as nxqndzbrw,--年度指标任务-收入&#xff08;万元&#xff09;ndzbwh.nsrndzbrw as nsrndzbrw,--年度指标任务-回款&#xff08;万…

大数据中的项目数据采集

Datax介绍 官网&#xff1a; DataX/introduction.md at master alibaba/DataX GitHub DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。 DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS…

C、Minimizing the Sum(线性dp)

思路&#xff1a; 用dp[i][j] 来表示前i个数操作了j次的最小和&#xff0c;然后对于每个a[i]&#xff0c;我们分别枚举i前面操作了x次以及后面操作了j次&#xff0c;对于每次操作&#xff0c;都是将一段区间全换位区间最小值. 代码&#xff1a; void solve(){int n, k;cin &…

基于SpringBoot+Vue大学生兼职管理系统的设计与实现

目录 一、前言介绍 二、功能需求 三、功能结构设计 四、管理员功能实现 招聘单位管理 用户管理 论坛管理 公告信息管理 五、招聘单位功能实现 职位招聘管理 职位留言管理 简历投递管理 六、用户功能实现 在线论坛 职位招聘信息 简历投递 简历 七、部分核心代码 …

代码随想录算法训练营第二十六天||39. 组合总和、40.组合总和II、131.分割回文串

文章目录 一、39. 组合总和 思路 二、40.组合总和II 思路 三、131.分割回文串 思路 一、39. 组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取…

活性炭复合纳米纤维膜

活性炭复合纳米纤维膜是一种结合了活性炭和纳米纤维技术的新型复合材料。这种材料通常通过特定的制备工艺&#xff0c;如静电纺丝技术&#xff0c;将活性炭纳米纤维与其他材料&#xff08;如TiO2、聚合物等&#xff09;结合在一起&#xff0c;形成具有良好结构和功能的薄膜。 活…

【SpringBoot】数据脱敏

文章目录 什么是数据脱敏JsonSerialize自定义Jackson注解定制脱敏策略定制JSON序列化实现脱敏工具类 定义Person类&#xff0c;对其数据脱敏模拟接口测试总结 什么是数据脱敏 数据脱敏&#xff0c;也称为数据的去隐私化或数据变形&#xff0c;是一种技术手段&#xff0c;用于对…

【酱浦菌-爬虫技术细节】解决学术堂爬虫翻页(下一页)问题

首先我们通过css选择器获取页码信息&#xff0c;这里的css选择器&#xff0c;选择的是含有a标签的所有li标签&#xff0c;代码如下&#xff1a; li html_web.css(div.pd_c_xslb_left_fenye ul li>a) for li in li:li_url li.css(a::attr(href)).get()li_num li.css(a::t…

排序算法:插入、希尔、选择、推排、冒泡、快速、归并排序

排序算法 目录 前言 一、排序的概念 1.1排序的概念 1.2 常见的排序算法 二、常见排序算法的实现 2.1 插入排序 2.2 希尔排序 2.3 选择排序 2.4 堆排序 2.5 冒泡排序 2.6 快速排序 2.6.1 hoare版本 2.6.2 前后指针版本 2.6.3 非递归版本 2.7 归并排序 归并排序 2.8 计数排序 三、…