目錄
一. 抽象類
1.1 抽象類概念
1.2 抽象類語法?
1.3 抽象類特性
1.4 抽象類的作用?
二. 接口?
2.1 接口的概念
?2.2 語法規則
2.3 接口的使用?
2.4 接口間的繼承
2.5 抽象類和接口的區別?
三. Object類?
3.1 toString() 方法
3.2 對象比較equals()方法?
3.3?hashcode方法?
一. 抽象類

?上述代碼: 在Dog中重寫了Animal中的eat(),? 在Bird中重寫了Animal中的eat()
而我們從來沒有用到過Animal中的eat(), 因為Animal不指代任何一種動物, 所以eat()無意義.?
那么我們是否可以將Animal中的eat()方法簡化呢?下面就引出了我們的抽象方法和抽象類
1.1 抽象類概念

例如上述代碼中的Animal中的eat(),?我們可以把它設計成一個 抽象方法(abstract method), 包含抽象方法的類Animal我們稱為 抽象類(abstract class).?
1.2 抽象類語法?

注意:抽象類也是類,內部可以包含普通方法和屬性,甚至構造方法?
1.3 抽象類特性
1. 抽象類不能直接實例化對象
?
// 編譯出錯Error :( 30 , 23 ) java : Shape 是抽象的 ; 無法實例化
?2. 抽象方法不能是 private 的
// 編譯出錯Error :( 4 , 27 ) java : 非法的修飾符組合 : abstract 和 private
?3. 抽象方法不能被final和static修飾,因為抽象方法要被子類重寫
// 編譯報錯:// Error:(20, 25) java: 非法的修飾符組合 : abstract 和 final// Error:(21, 33) java: 非法的修飾符組合 : abstract 和 static
4. 抽象類必須被繼承,并且繼承后子類要重寫父類中的抽象方法,否則子類也是抽象類,必須要使用 abstract 修飾 ??
![]()
或
1.4 抽象類的作用?
很多語法存在的意義都是為了 " 預防出錯 ", 例如我們曾經用過的 final 也是類似 . 創建的變量用戶不去修改 , 不就相當于常量嘛? 但是加上 final 能夠在不小心誤修改的時候 , 讓編譯器及時提醒我們 .充分利用編譯器的校驗 , 在實際開發中是非常有意義的.
二. 接口?
2.1 接口的概念
在現實生活中,接口的例子比比皆是,比如:筆記本上的USB口,電源插座等。
電腦的USB口上,可以插:U盤、鼠標、鍵盤...所有符合USB協議的設備
電源插座插孔上,可以插:電腦、電視機、電飯煲...所有符合規范的設備
?2.2 語法規則
public interface 接口名稱 {}
public interface 接口名稱 {????????public void method1 (); //沒加abstract? 但也默認為抽象方法}
3.? 接口當中的定義的方法, 默認都是public abstract修飾的(只能是public abstract,其他修飾符都會報錯), 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現 .
public interface 接口名稱 {????????public abstract void method1 (); // public abstract 是固定搭配,可以不寫????????void method4 ();// 注意:在接口中上述寫法都是抽象方法,更推薦省略寫法}
?4. 如果想要有具體的實現, 必須由default或static修飾
5.? 接口當中定義的成員變量, 默認是public static final修飾的
public interface USB {????????double brand = 3.0 ; // 默認被: final public static 修飾}public class TestUSB {????????public static void main ( String [] args ) {????????????????System . out . println ( USB . brand ); // 可以直接通過接口名訪問,說明是靜態的????????????????USB . brand = 2.0 ;????????????????// 編譯報錯:Error:(12, 12) java: 無法為最終變量 brand 分配值????????????????// 說明brand具有 final 屬性????????}}
6.?接口類型是一種引用類型,但是不能直接new接口的對象
public class TestUSB {????????public static void main ( String [] args ) {????????????????USB usb = new USB ();????????}}// Error:(10, 19) java: day20210915.USB 是抽象的 ; 無法實例化
7. 接口中不能有靜態代碼塊和構造方法?
9.?如果類沒有實現接口中的所有的抽象方法,則類必須設置為抽象類?
2.3 接口的使用?
public class 類名稱 implements 接口名稱 {????????// ...}
?注: 一個類只能繼承一個普通類/抽象類, 但是可以實現多個接口(有什么特征就實現什么接口)
接下來我們舉個例子:
通過類來表示動物.
?
另外我們再提供一組接口 , 分別表示 " 會飛的 ", " 會跑的 ", " 會游泳的 ".![]()
![]()
接下來我們創建幾個具體的動物:鳥, 是個動物, 會飛會跑
狗, 是個動物, 會跑會游泳
鴨子, 是個動物, 會跑,會游泳, 會飛
注意:一個類實現多個接口時,每個接口中的抽象方法都要實現,否則類必須設置為抽象類 。使用:
結果:![]()
上面的代碼展示了 Java 面向對象編程中最常見的用法: 一個類繼承一個父類, 同時實現多種接口.
繼承表達的含義是 is - a 語義, 而接口表達的含義是 具有 xxx 特性 . ?
例如上述代碼, 再定義一個非動物對象![]()
結果為:![]()
只要該對象具有這種性質, 就可以實現對應的接口.?
2.4 接口間的繼承
例如上述代碼, 青蛙屬于兩棲動物, 我們可以定義一個兩棲動物的接口, 繼承IRun,ISwim接口![]()
![]()
接口間的繼承相當于把多個接口合并在一起.?
2.5 抽象類和接口的區別?

三. Object類?
class Person {}class Student {}public class Test {????????public static void function ( Object obj ) {? ? ? ? ? ? ??????????}????????public static void main ( String [] args ) {????????????????function ( new Person ());????????????????function ( new Student ());????????}}
所以在開發之中,Object類是參數的最高統一類型。但是Object類也存在有定義好的一些方法,在子類中可以進行使用。?

3.1 toString() 方法
// Object 類中的 toString() 方法實現:public String toString () {????????return getClass (). getName () + "@" + Integer . toHexString ( hashCode ());}
打印結果為:
那么println內部是怎么實現的呢?按住ctrl我們點進去可以看到:
傳過去Son類型的son, 用Object接收,發生了向上轉型, 將x傳到了String.valueOf這個方法里.按住Ctrl我們繼續點進去查看:
調用了Object類的toString方法, 按住Ctrl我們進去點進去:
就看到了我們所輸入的結果.?
所以:
我們直接拿來用的這一行代碼 System.out.println(son);? ,實際上是發生了向上轉型, 通過父類也就是Object類中的toString方法實現的.?
那么如果我們在子類中自己定義一個toString方法,是否可以發生重寫呢?
此時輸出的結果為:
?
?答案是肯定的, 即在子類中自己定義一個toString方法,可以重寫Object中的toString方法.
3.2 對象比較equals()方法?
// Object 類中的 equals 方法public boolean equals ( Object obj ) {????????return ( this == obj ); // 使用引用中的地址直接來進行比較}
?例如:
class Person {????????private String name ;????????private int age ;????????public Person ( String name , int age ) {????????????????this . age = age ;????????????????this . name = name ;????????}}public class Test {????????public static void main ( String [] args ) { ????????????????????????????int a = 10 ;????????????????int b = 10 ;????????????????System . out . println ( a == b ); // 輸出 true????????????? ? Person p1 = new Person ( "gaobo" , 20 ) ;????????????????Person p2 = new Person ( "gaobo" , 20 ) ;????????????????System . out . println ( p1 == p2 ); // 輸出 false????????????????System . out . println ( p1 . equals ( p2 )); // 輸出 false????????}}
Person類重寫equals方法后,然后比較:
class Person {...????????@Override????????public boolean equals ( Object obj ) {????????????????if ( obj == null ) {????????????????????????return false ;????????????????}????????????????if ( this == obj ) {????????????????????????return true ;????????????????}????????????????// 不是Person 類對象????????????????if ( ! ( obj instanceof Person )) {????????????????????????return false ;????????????????}????????Person person = ( Person ) obj ; // 向下轉型,比較屬性值????????return this . name . equals ( person . name ) && this . age == person . age ;????????}}
結論:比較對象中內容是否相同的時候,一定要重寫equals方法?
3.3?hashcode方法?
public native int hashCode ();
class Person {????????public String name ;????????public int age ;????????public Person ( String name , int age ) {????????????????this . name = name ;????????????????this . age = age ;????????}}public class TestDemo4 {????????public static void main ( String [] args ) {????????????????Person per1 = new Person ( "haha" , 20 ) ;????????????????Person per2 = new Person ( "haha" , 20 ) ;????????????????System . out . println ( per1 . hashCode ());????????????????System . out . println ( per2 . hashCode ());????????}}// 執行結果4601419581163157884
class Person {????????public String name ;????????public int age ;????????public Person ( String name , int age ) {????????????????this . name = name ;????????????????this . age = age ;????????}????????@Override????????public int hashCode () {????????????????return Objects . hash ( name , age );????????}}public class TestDemo4 {????????public static void main ( String [] args ) {????????????????Person per1 = new Person ( "haha" , 20 ) ;????????????????Person per2 = new Person ( "haha" , 20 ) ;????????????????System . out . println ( per1 . hashCode ());????????????????System . out . println ( per2 . hashCode ());????????}}// 執行結果460141958460141958
?哈希值一樣
?