零基礎 “入坑” Java--- 十三、再談類和接口

文章目錄

  • 一、Object類
    • 1.獲取對象信息
    • 2.對象比較:equals方法
  • 二、再談接口
    • 1.比較相關接口
    • 2.Cloneable接口和深拷貝
  • 三、內部類
    • 1.匿名內部類
    • 2.實例內部類
    • 3.靜態內部類
    • 4.局部內部類

在之前的學習中,我們已經了解了有關類以及接口的知識,在本章節中,我們繼續來探究類和接口相關的知識。

一、Object類

Object類是Java默認提供的一個類。在Java中,除了Object類,其余所有的類都存在繼承關系,默認繼承Object類。即所有類實例化出的對象都可以使用Object類的引用接收,如:

class A {}
class B {}
public class Test {public static void test(Object object) {System.out.println(object);}public static void main(String[] args) {test(new A());test(new B());}
}

Object類中也存在一些定義好的方法,在編寫代碼過程中經常使用,接下來我們就來學習一下。

1.獲取對象信息

如果想要打印對象中的內容,可以通過重寫toString的方式來完成,這一點在之前的學習中也已經介紹過,我們來看一下源碼即可:
在這里插入圖片描述

查看源碼方式:雙擊Shift,因為toString方法在Object類中,所以輸入Object,再尋找toString方法即可。

2.對象比較:equals方法

在Java中,使用 == 進行比較時:

a.如果 == 兩邊為基本數據類型,則比較的是變量的值是否相同。
b.如果 == 兩邊為引用類型,則比較的是"地址"是否相同。
c.當 == 兩邊為引用類型時,如果想比較其內容是否相同,就可以重寫Object中的equals方法,使用equals進行比較(equals默認按照"地址"進行比較)。

舉個例子:

class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}
}
public class Test {public static void main(String[] args) {Person person = new Person("小王", 20);Person person1 = new Person("小王", 20);System.out.println(person.equals(person1));}
}

定義一個Person類,實例化兩個對象,并將其姓名和年齡都進行了統一,沒重寫equals方法時,運行結果為"false"。

class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
public class Test {public static void main(String[] args) {Person person = new Person("小王", 20);Person person1 = new Person("小王", 20);System.out.println(person.equals(person1));}
}

當我們重寫了equals方法之后,此時運行結果就為"true"。

重寫equals方法也很簡單:在空行單擊鼠標右鍵選擇生成,再選擇equals() 和 hashCode(),再一直點擊下一步即可:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
當涉及到需要比較對象中的內容是否相同時,一定要重寫equals方法。

對于什么是hashCode(),等我們學習完哈希表之后就會知道。

二、再談接口

1.比較相關接口

我們來看這樣一個例子:

class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public class Test {public static void main(String[] args) {Person person = new Person("小王", 20);Person person1 = new Person("小李", 18);}
}

我們定義一個Person類,實例化兩個對象,現在我們想比較兩個對象的大小:

    public static void main(String[] args) {Person person = new Person("小王", 20);Person person1 = new Person("小李", 18);System.out.println(person > person1); //error}

對于二元運算符,兩邊的操作數應該為基本數據類型,但此時比較的為引用類型的數據,并不能進行比較。如果我們想比較引用類型的數據,可以實現一個接口:

class Person implements Comparable<Person> {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Person o) {//原始語句//return 0;if (this.age > o.age) {return 1;} else if (this.age < o.age) {return -1;} else {return 0;}}
}
public class Test {public static void main(String[] args) {Person person = new Person("小王", 20);Person person1 = new Person("小李", 18);System.out.println(person.compareTo(person1)); //1}
}

我們實現Comparable接口,"<>"中的為類名,并重寫compareTo方法;在這個例子中,我們根據年齡的大小比較兩個數據。

重寫方法可以使用鼠標右鍵,生成的方式完成。

對于自定義類型,要想比較大小,就需要實現Comparable這個接口,實現這個接口就需要重寫compareTo方法:
在這里插入圖片描述
對于compareTo方法中的實現邏輯,還可以寫為:

    public int compareTo(Person o) {return this.age - o.age;}

返回值為兩個數據中年齡的差值。

equals和compareTo:equals比較的是 是否相等,返回值為布爾類型;compareTo比較的是 大小關系,返回值為整型。

使用Comparable這個接口雖然能解決比較大小的問題,但這個接口對類的侵入性較強:在上面這個例子中,我們通過年齡對 對象進行比較,但當我們想根據其他變量比較大小時,就需要重新編寫和比較相關的所有的代碼,修改成本過高。

我們可以通過Comparator這個接口來解決這個問題:

class Person {public String name;public int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}
//根據年齡比較
class AgeCom implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {//原始語句//return 0;return o1.age - o2.age;}
}
//根據姓名比較
class NameCom implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {//name為String類型,String中實現了Comparable接口,重寫了compareTo方法return o1.name.compareTo(o2.name);}
}
public class Test {public static void main(String[] args) {Person person = new Person("小王", 20);Person person1 = new Person("小李", 18);//實例化對象,通過對象調用類中的方法AgeCom ageCom = new AgeCom();System.out.println(ageCom.compare(person, person1));NameCom nameCom = new NameCom();System.out.println(nameCom.compare(person, person1));}
}

在實現Comparator接口時,我們需要根據比較的邏輯重寫compare方法。 實現Comparator接口后,代碼的修改和增加 效率更高,使用更方便。

2.Cloneable接口和深拷貝

class Person {public String name;public int age;public Person(int age) {this.age = age;}//重寫clone方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}
}
public class Test {public static void main(String[] args) {Person person = new Person(20);Person person1 = person.clone();}
}

此時代碼并不能正常運行,會編譯報錯,我們需要解決三處錯誤才能使代碼正常運行:
在這里插入圖片描述
第一處錯誤是有關異常的知識,我們之后會學習到。

第三處錯誤:
Cloneable接口的源碼為:
在這里插入圖片描述
我們稱之為空接口/標記接口,其作用為:證明當前類是可以被克隆的。

我們還需要注意一點:
在這里插入圖片描述


解決完這三處問題后,代碼就可以正常運行了:

class Person implements Cloneable {public String name;public int age;public Person(int age) {this.age = age;}//重寫clone方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person = new Person(20);Person person1 = (Person) person.clone();System.out.println(person);System.out.println(person1);}
}

運行結果為:
在這里插入圖片描述
執行圖為:
在這里插入圖片描述


我們對代碼做出如下修改:

class Money {public double money = 66.6;
}
class Person implements Cloneable {public String name;public int age;//組合思想public Money m;public Person(int age) {this.age = age;this.m = new Money();}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Person{" +"age=" + age +'}';}
}
public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person person = new Person(20);Person person1 = (Person) person.clone();System.out.println(person.m.money); //66.6System.out.println(person1.m.money); //66.6System.out.println("===============");person1.m.money = 88.8;System.out.println(person.m.money); //88.8System.out.println(person1.m.money); //88.8}
}

我們使用組合的思想增加一個成員變量,并在構造方法中為其實例化一個對象。我們想修改person1的值,但最后卻將person和person1的值都修改了。

在修改值的過程中,會發生如下邏輯
在這里插入圖片描述
此時發生的這種現象,我們就稱之為淺拷貝淺拷貝并沒有將 對象中的對象進行克隆

但我們只想修改person1的值,應該怎么辦呢?

我們對代碼進行修改:

//實現接口
class Money implements Cloneable {public double money = 66.6;//重寫方法@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

對于Person類中的clone方法的內容進行修改 (核心!!!)

    @Overrideprotected Object clone() throws CloneNotSupportedException {//return super.clone();Person tmp = (Person) super.clone();tmp.m = (Money) this.m.clone();return tmp;}

修改完以上兩處,再次運行代碼,只有person1的值被修改了。

流程圖為:
在這里插入圖片描述
此時發生的這種現象,我們就稱之為深拷貝區分深淺拷貝主要取決于代碼的實現過程。

三、內部類

在Java中,可以將一個類定義在另一個類或者方法的內部,前者稱為內部類,后者稱為外部類。 內部類也是封裝思想的一種體現。

內部類可以分為:靜態內部類、實例內部類、匿名內部類、局部內部類(幾乎不用)。

class A {class B {//實例內部類}static class C {//靜態內部類}
}
interface D {void test();
}
public class Test {public static void main(String[] args) {new D() {@Overridepublic void test() {}}; //匿名內部類}
}

在編譯之后,內部類也會生成獨立的字節碼文件。一個類對應一個字節碼文件。

1.匿名內部類

對于匿名內部類,可以使用以下兩種方式調用類中的方法:

        //方式一new D() {@Overridepublic void test() {System.out.println("嘻嘻");}}.test(); //匿名內部類
        //方式二D d = new D() {@Overridepublic void test() {System.out.println("嘻嘻");}}; //匿名內部類d.test();

對于匿名內部類我們可以認為:有一個類實現了一個接口,并在類中重寫了接口中的方法。


    public static void main(String[] args) {int ret = 100;D d = new D() {@Overridepublic void test() {System.out.println("值為:" + ret);}}; //匿名內部類d.test();}

在匿名內部類中可以使用初始化的變量,

    public static void main(String[] args) {int ret = 100;ret = 200;D d = new D() {@Overridepublic void test() {System.out.println("值為:" + ret); //error}}; //匿名內部類d.test();}

但當變量的值被修改后,代碼就會報錯。在匿名內部類中,不能訪問被修改的數據。

2.實例內部類

我們再來看實例內部類:

class Outer {public int a = 1;private int b = 2;public static int c = 3;//實例內部類class Inner {public int x = 1;private int y = 2;public void test() {System.out.println("內部類");}}public void test() {System.out.println("外部類");}
}
public class Test2 {public static void main(String[] args) {//實例化對象//方式一Outer.Inner inner = new Outer().new Inner();//方式二Outer outer = new Outer();Outer.Inner inner1 = outer.new Inner();System.out.println(inner.x); //1inner.test(); //內部類}
}

在使用內部類時,內部類的實例化需要通過外部類才能實現。

    class Inner {public int x = 1;private int y = 2;public static int y = 3;public void test() {System.out.println("內部類");}}

我們在實例內部類中添加一個靜態成員變量,會報錯,這是因為:static修飾的成員不依賴于對象,而內部類卻需要依賴于外部類對象。

        public static final int z = 3;

使用final關鍵字修飾就可以解決這個錯誤,final修飾的為常量。


    class Inner {public int a = 666;public int x = 1;private int y = 2;public static final int z = 3;public void test() {System.out.println("內部類");System.out.println(a); //666System.out.println(Outer.this.a); //1}}

當外部類和實例內部類中存在同名的成員變量時,優先訪問實例內部類中的成員變量;如果想要訪問外部類中的成員變量,需要使用 “外部類類名.this.成員變量” 的方式訪問。

實例內部類也受訪問修飾限定符的約束。

3.靜態內部類

class Outer1 {public int a = 1;private int b = 2;public static int c = 3;//靜態內部類static class Inner {public int x = 1;private int y = 2;public static int z = 3;public void test() {System.out.println(x); //1System.out.println(c); //3//a為非靜態System.out.println(a); //errorSystem.out.println("內部類");}}
}
public class Test3 {public static void main(String[] args) {//實例化Outer1.Inner inner = new Outer1.Inner();inner.test();}
}

靜態內部類的實例化也較為特殊,需注意。

在靜態內部類中不可以直接調用靜態內部類外的 非靜態的成員。如果想訪問,需要通過外部類對象進行訪問:

        public void test() {System.out.println(x); //1System.out.println(c); //3//實例化外部類對象Outer1 outer1 = new Outer1();//通過外部類對象訪問System.out.println(outer1.a); //1System.out.println("內部類");}

4.局部內部類

    public void test() {//局部內部類class Inner {public int num = 1;}Inner inner = new Inner();System.out.println(inner.num);}

局部內部類只能在當前定義的 方法體的 內部使用,不能被訪問修飾限定符 修飾,很少使用。


Ending。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915429.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915429.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915429.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring Boot 一個注解搞定「加密 + 解密 + 簽名 + 驗簽」

Spring Boot 一個注解搞定「加密 解密 簽名 驗簽」本文基于 Spring Boot 3.x&#xff0c;通過一個自定義注解 AOP&#xff0c;一行注解即可給任何 Controller 方法加上 請求解密 → 驗簽 → 響應加密 → 加簽 的完整鏈路&#xff0c;并可直接拷貝到生產環境使用。一、最終效…

《計算機網絡》實驗報告二 IP協議分析

目 錄 1、實驗目的 2、實驗環境 3、實驗內容 3.1 tcpdump 基本用法 3.2 wireshark基本用法 3.3 利用tcpdump抓包&#xff0c;wireshark分析包 4、實驗結果與分析 4.1 tcpdump命令的基本用法 4.2 wireshark的基本用法 4.3 利用tcpdump抓包&#xff0c;wireshark分析包…

k8s學習記錄(三):Pod基礎-Node選擇

一、前言 在上一篇文章中我們學習了Pod的一些基本的知識&#xff0c;今天我們將繼續學習Pod。 二、K8S如何選擇節點來運行Pod 我們知道在一個K8S集群中&#xff0c;會有多個工作節點&#xff08;Worker Node&#xff09;&#xff0c;那么k8s會選擇那個node呢&#xff1f;接下…

3天功能開發→3小時:通義靈碼2.0+DEEPSEEK實測報告,單元測試生成準確率92%的秘密

活動鏈接&#xff1a;https://developer.aliyun.com/topic/lingma-aideveloper?spma2c6h.29979852.J_9593490300.2.49b8110eeymlF8 前言 隨著人工智能技術的迅猛發展&#xff0c;AI 賦能編程成為了必然趨勢。通義靈碼應運而生&#xff0c;它是阿里巴巴集團在人工智能與編程領…

【小沐學GIS】基于Rust繪制三維數字地球Earth(Rust、OpenGL、GIS)

&#x1f37a;三維數字地球GIS系列相關文章如下&#x1f37a;&#xff1a;1【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐學GIS】基于C繪制三維數字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第二期3【小沐學GI…

ARM 學習筆記(三)

參考文獻&#xff1a;《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》《ARM Cortex-A (ARMv7-A) Series Programmer’s Guide》1、內存類型 ARMv7-A 處理器中&#xff0c;將 Memory 定義為幾種類型&#xff08;Memory Type&#xff09;&#xff1a; Strong…

Flask 框架(一):核心特性與基礎配置

目錄 一、為什么選擇 Flask&#xff1f; 二、Flask 核心概念與初始化 2.1 程序實例初始化 2.2 運行配置&#xff1a;app.run () 參數詳解 2.3 應用配置&#xff1a;三種參數設置方式 1. 字典直接配置&#xff08;簡單臨時場景&#xff09; 2. 配置文件導入&#xff08;生…

社交圈子系統開源社交源碼 / 小程序+H5+APP 多端互通的底層技術分析

伴隨社交產品向“圈子化”、“內容驅動”發展方向演進&#xff0c;打造一套支持小程序、H5、APP 互通的社交圈子系統&#xff0c;已經成為構建垂直社區的基礎架構能力要求。本文圍繞一套典型的多端社交興趣平臺&#xff08;即友貓社區平臺&#xff09;的設計實踐&#xff0c;對…

gitlab-runner配置問題記錄

引言 筆者曾通過2種方式部署過 gitlab-runner&#xff0c;在 gitlab 中使用這個 runner 拉起 ci job 的過程中或多或少遇到些問題&#xff0c;主要都是 job 中無法訪問宿主機的docker 等組件。本篇文檔主要記錄 gitlab-runner 安裝及相關配置。 二進制部署 gitlab-runner 部署 …

每日面試題10:令牌桶

令牌桶算法&#xff1a;優雅的流量控制藝術在現代分布式系統中&#xff0c;流量控制如同交通信號燈般重要——它既不能讓請求"堵死"系統&#xff0c;也不能放任流量"橫沖直撞"。令牌桶算法&#xff08;Token Bucket Algorithm&#xff09;正是這樣一種精妙…

【java】消息推送

文章目錄Java網頁消息推送解決方案 短輪詢、長輪詢、SSE、Websocket

STM32 | 有源蜂鳴器響,無源蜂鳴器播音樂

目錄 Overview 有源蜂鳴器 無源蜂鳴器 有源蜂鳴器控制 GPIO配置 控制程序 無源蜂鳴器控制 反轉GPIO控制 GPIO配置 控制接口 PWM控制 GPIO配置 控制函數 改變頻率播音樂 原理 1. 頻率決定音調 2. 占空比決定音量 GPIO初始化 結構體定義和音符頻率表 播放接口 …

第十四章 gin基礎

文章目錄Gin快速搭建一個web服務Gin數據交互JSON串內容規范Gin使用結構體返回數據給前端Gin配置POST類型的路由Gin獲取GET請求參數Gin獲取POST請求參數-form-data類型Gin獲取POST請求參數-JSON類型Gin獲取參數綁定至結構體Gin快速搭建一個web服務 下載包 \\新建一個文件&…

Baumer工業相機堡盟工業相機如何通過YoloV8的深度學習模型實現PCB的缺陷檢測(C#代碼,UI界面版)

Baumer工業相機堡盟工業相機如何通過YoloV8的深度學習模型實現PCB的缺陷檢測&#xff08;C#代碼&#xff0c;UI界面版&#xff09;工業相機使用YoloV8模型實現PCB的缺陷檢測工業相機實現YoloV8模型實現PCB的缺陷檢測的技術背景在相機SDK中獲取圖像轉換圖像的代碼分析工業相機圖…

【Vivado那些事兒】AMD-XILINX 7系列比特流加密

前提&#xff1a;加密有風險&#xff0c;操作需謹慎前言在許多項目中&#xff0c;經過漫長的等待&#xff0c;我們的 FPGA 設計終于可以投入現場部署了。前期的資金的投入及知識產權的保護&#xff0c;我們需要對現場部署的 FPGA 進行比特流保護以防止逆向工程和未經授權的重復…

RK3588 安卓adb操作

adb&#xff08;Android Debug Bridge&#xff09;是一個用于與安卓設備進行通信和控制的工具。adb可以通過USB或無線網絡連接安卓設備&#xff0c;執行各種命令&#xff0c;如安裝和卸載應用&#xff0c;傳輸文件&#xff0c;查看日志&#xff0c;運行shell命令等。adb是安卓開…

【華為機試】70. 爬樓梯

文章目錄70. 爬樓梯描述示例 1示例 2提示解題思路核心分析問題建模算法實現方法1&#xff1a;動態規劃&#xff08;標準解法&#xff09;方法2&#xff1a;空間優化動態規劃&#xff08;最優解&#xff09;方法3&#xff1a;遞歸 記憶化方法4&#xff1a;數學公式&#xff08;…

山東大學軟件學院面向對象期末復習

面向對象 文章目錄面向對象04 類封裝接口 抽象類05 消息&#xff0c;實例化&#xff0c;靜態變量方法消息動/靜態類型語言對象創建類及實例具有下面特征對象數組的創建靜態數據成員構造函數06_0 繼承繼承是向下傳遞的JAVA為什么不支持多重繼承繼承的形式特殊化繼承替換原則規范…

讓 Windows 用上 macOS 的系統下載與保姆級使用教程

模擬蘋果桌面軟件下載&#xff1a;https://xpan.com.cn/s/8NFAGT 還記得 Windows 11剛發布時&#xff0c;很多人就說“果里果氣"的&#xff0c;但界面確實做的漂亮。 不知道現在有多少小伙伴正用著macOS&#xff0c;不過我敢確定&#xff0c;喜歡macOS的人絕對不少&#…

嵌入式硬件篇---繼電器

繼電器是一種通過小電流控制大電流的電磁開關&#xff0c;廣泛應用于自動化控制、電力系統和電子設備中。以下從工作原理、應用場景和電路特點三個方面詳細介紹&#xff1a;一、工作原理繼電器本質是電磁控制的機械式開關&#xff0c;核心部件包括&#xff1a;線圈&#xff08;…