1.抽象類
1.1
在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。
在打印圖形例子中, 我們發現, 父類 Shape 中的 draw 方法好像並沒有什麼實際工作, 主要的繪製圖形都是由 Shape 的各種子類的 draw 方法來完成的。像這種沒有實際工作的方法, 我們可以把它設計成一個抽象方法(abstract method), 包含抽象方法的類我們稱為抽象類(abstract class)。
1.2 語法
在Java中,一個類如果被 abstract 修飾稱為抽象類,抽象類中被 abstract 修飾的方法稱為抽象方法,抽象方法不用給出具體的實現體,只保留方法的名字參數信息。
// 抽象類也是類,也可以增加普通方法和屬性
public abstract class Shape {
// 抽象方法不能寫方法的具體實現 即沒有方法體
public abstract void draw();
// 形狀的面積. 抽象類可以包含屬性
private double area;
private static int n = 0;
// 也可以包含普通的方法
public double getArea() {
return area;
}
// 也可以包含靜態方法
public static int getCount() {
return n;
}
}
1.3 特性
(1)抽象類不能直接實例化對象
(2)抽象方法不能是 private 的,也不能被final和static修飾,因為抽象方法要被子類重寫。
(3)抽象類必須被繼承,並且繼承後子類必須要重寫父類中的抽象方法(用的更多)也是抽象類(要使用 abstract 修飾)。
(4)抽象類中不一定包含抽象方法,但是有抽象方法的類一定是抽象類
(5)抽象類中可以有構造方法,供子類創建對象時,初始化父類的成員變量。
1.4
2.接口
2.1 概念
在現實生活中,接口的例子比比皆是,比如:筆記本上的USB口,電源插座等。
電腦的USB口上,可以插:U盤、鼠標、鍵盤...所有符合USB協議的設備;電源插座插孔上,可以插:電腦、電視機、電飯煲...所有符合規範的設備。
通過上述例子可以看出:接口就是公共的行為規範標準,大家在實現時,只要符合規範標準,就可以通用。
在Java中,接口可以看成:多個類的公共規範,是一種引用數據類型。
2.2
接口的定義格式與定義類的格式基本相同,將class關鍵字換成 interface 關鍵字,就定義了一個接口。
// 對於接口來説, 裏面不能包含屬性,
// 包含的方法也只能是抽象方法.
public interface Drawable {
void draw();
}
public interface Drawable {
public static final int count = 0;
void draw();
}
2.3
接口不能直接使用,必須要有一個 "實現類" 來 "實現" 該接口,實現接口中的所有抽象方法。
注意:子類和父類之間是extends 繼承關係,類與接口之間是 implements 實現關係。
public class Mouse implements USB {
@Override
public void openDevice() {
System.out.println("插入鼠標");
}
@Override
public void closeDevice() {
System.out.println("拔出鼠標");
}
}
public class KeyBoard implements USB {
@Override
public void openDevice() {
System.out.println("插入鍵盤");
}
@Override
public void closeDevice() {
System.out.println("拔出鍵盤");
}
}
public class Test {
public static void main(String[] args) {
USB usb = new Mouse();
usb.openDevice();
usb.closeDevice();
usb = new KeyBoard();
usb.openDevice();
usb.closeDevice();
}
}
2.4
(1) 接口類型是一種引用類型,但是不能直接new接口的對象。
(2)接口中每一個方法都是public的抽象方法, 即接口中的方法會被隱式的指定為 public abstract(只能是 public abstract,其他修飾符都會報錯)。
(3)接口中的方法是不能在接口中實現的,只能由實現接口的類來實現。
(4)重寫接口中方法時,不能使用默認的訪問權限
(5)接口中可以含有變量,但是接口中的變量會被隱式的指定為 public static final 變量。
(6)接口中不能有靜態代碼塊和構造方法。
(7)接口雖然不是類,但是接口編譯完成後字節碼文件的後綴格式也是.class
(8)如果類沒有實現接口中的所有的抽象方法,則類必須設置為抽象類。
(9)jdk8中:接口中還可以包含default方法。
2.5
在Java中,類和類之間是單繼承的,一個類只能有一個父類,即Java中不支持多繼承,但是一個類可以實現多個接口。
下面通過類來表示一組動物,另外我們再提供一組接口, 分別表示 "會跑的", "會游泳的"。
注意:一個類實現多個接口時,每個接口中的抽象方法都要實現,否則類必須設置為抽象類。
提示,:IDEA 中使用 ctrl + i 快速實現接口
2.6
2.7
兩種方式對比
2.8
(1)Clonable 接口
Java 中內置了一些很有用的接口, Clonable 就是其中之一。
Object 類中存在一個 clone 方法, 調用這個方法可以創建一個對象的 "拷貝"。但是要想合法調用 clone 方法, 必須要先實現 Clonable 接口, 否則就會拋出 CloneNotSupportedException 異常。
(2)淺拷貝vs深拷貝
Cloneable 拷貝出的對象是一份 "淺拷貝"
2.9 抽象類和接口的區別
3.匿名內部類
import java.util.Comparator;
public class Test4 {
public static void main(String[] args) {
// 需要給 Test4 這個類, 創建 Comparator 比較器
Comparator<Test4> comparator = new Comparator<Test4>() {
@Override
public int compare(Test4 o1, Test4 o2) {
return 0;
}
};
Test4 t1 = new Test4();
Test4 t2 = new Test4();
int ret = comparator.compare(t1, t2);
System.out.println(ret);
}
}
4.Object類
Object是Java默認提供的一個類。Java裏面除了Object類,所有的類都是存在繼承關係的,默認繼承Object父類,即所有類的對象都可以使用 Object 的引用進行接收。
所以在開發之中,Object 類是參數的最高統一類型,且 Object 類也存在有定義好的一些方法。
4.1
如果要打印對象中的內容,可以直接重寫 Object 類中的 toString() 方法,之前已經講過了,此處不再累贅。
Java 中的引用類型主要包括:
類類型(內置類【String 類、包裝類、系統類】、自定義類)、接口類型、數組類型、枚舉類型、註解類型。
所有引用類型的共同特點是:變量存儲的是對象的內存地址,而不是對象本身的值。這是理解 Java 面向對象編程和內存管理的關鍵。
4.2 equals--對象比較
在Java中比較對象:
== 運算符用於比較兩個對象的引用是否指向同一塊內存地址【內存角度】或 兩個引用變量是否指向同一個對象(即內存地址是否相同)【對象角度】
equals 方法默認情況下(在Object類中)也是比較引用是否相同,即與 == 的行為相同。
但是,許多類(如 String 類)重寫了 equals 方法,此時就會去比較兩個字符串的內容是否相同,而不是比較它們是否指向同一個對象。
結論:比較對象中內容是否相同的時候,一定要重寫equals方法。
代碼
public class LianXi {
public static void main(String[] args) {
Student s1 = new Student(1, "張三", 90);
Student s2 = new Student(1, "張三", 90);
// 此處針對上述對象是比較兩個引用的指向是否相同,不相同
System.out.println(s1 == s2); //false
// 若想比較內容, 就可以使用 equals 方法
// 但Object 中默認的 equals 還是比較 ==
// 比較內容就需要根據具體的類, 重寫 equals 方法! 在Student中
System.out.println(s1.equals(s2)); //true
}
}
public class Student {
private int id;
private String name;
private double score;
public Student(int id, String name, double score) {
this.id = id;
this.name = name;
this.score = score;
}
//……get set 方法
@Override
public boolean equals(Object o) {
if (o == null) {
// this 肯定不是 null
return false;
}
if (this == o) {
// 如果兩個引用指向同一個對象, 當然值也是相等的
return true;
}
if (!(o instanceof Student)) {
// 使用 instanceof 檢查傳入對象是否是 Student 類型或其子類
// ! 傳入的參數類型和當前 Student 不匹配.
return false;
}
// 只比較兩個 Student 的id 字段,認為學號相同就是同一個學生
// 將對象轉換為 Student 類型
Student other = (Student) o;
return this.id == other.id;
}
}