Openstack Train(系統Centos7.6)之三:配置資料庫,管理端haproxy配置環境服務
抽象類與介面
抽象類
在面向物件的概念中,所有的物件都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪物件的,如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類。
抽象類並不能被例項化,類的功能依然存在,成員變數,方法和構造方法的訪問方式同普通類。
抽象類必須被繼承才能被使用。
一個類只能繼承一個抽象類,但一個類可以實現多個介面。
Java 提供一個叫做抽象方法的機制,宣告語法如下
abstract void f();
但這個方法是不完整的;只有宣告沒有方法體。包含抽象方法的類叫做抽象類。如果一個類包含一個或多個抽象方法,那麼類本身也必須限定為抽象的,否則,編譯器會報錯。
abstract class a{
abstract void f();
}
這個類是不完整的,如果建立一個繼承抽象類的新類併為之建立物件,那麼就必須為基類的所有抽象方法提供方法定義。如果不這麼做,當然也可以選擇這麼做,新類仍然是一個抽象類,編譯器會強制我們給新類加上 abstract 關鍵字。
可以將一個不包含任何抽象方法 的類指定為抽象類,這樣做沒什麼意義,但可以阻止 建立此類的物件。
abstract class a { int f() { return 111; } // No abstract methods } public class AbstractWithoutAbstracts { // a b3 = new a(); // error: a is abstract; cannot be instantiated }
為了建立可初始化的類,就必須繼承此抽象類,併為所有的抽象方法新增定義。
相當於重寫基類的抽象方法。
// interfaces/Instantiable.java abstract class Uninstantiable { abstract void f(); abstract int g(); } public class Instantiable extends Uninstantiable { @Override void f() { System.out.println("f()"); } @Override int g() { return 22; } public static void main(String[] args) { Uninstantiable ui = new Instantiable(); } }
抽象類是允許所有的修飾符的,但是 private abstract 是被禁止的 因為子類必須重寫基類的抽象方法。
// interfaces/AbstractAccess.java
abstract class AbstractAccess {
private void m1() {}
// private abstract void m1a(); // illegal
protected void m2() {}
protected abstract void m2a();
void m3() {}
abstract void m3a();
public void m4() {}
public abstract void m4a();
}
介面
除非實現介面的類是抽象類,否則該類要定義介面中的所有方法。
介面無法被例項化,但是可以被實現。一個實現介面的類,必須實現介面內所描述的所有方法,否則就必須宣告為抽象類。另外,在 Java 中,介面型別可用來宣告一個變數,他們可以成為一個空指標,或是被繫結在一個以此介面實現的物件。
介面與類的區別:
介面不能用於例項化物件。
介面沒有構造方法。
介面中所有的方法必須是抽象方法。
介面不能包含成員變數,除了 static 和 final 變數。
介面不是被類繼承了,而是要被類實現。
介面支援多繼承。
介面特性
介面中每一個方法也是隱式抽象的,介面中的方法會被隱式的指定為 public abstract(只能是 public abstract,其他修飾符都會報錯)。
介面中可以含有變數,但是介面中的變數會被隱式的指定為 public static final 變數(並且只能是 public,用 private 修飾會報編譯錯誤)。
介面中的方法是不能在介面中實現的,只能由實現介面的類來實現介面中的方法。
注:JDK 1.8 以後,接口裡可以有靜態方法和方法體了。
建立介面
使用 interface
建立介面
public interface PureInterface {
int m1();
void m2();
double m3();
}
在 Java 8之前我們可以這麼說:interface 關鍵字產生一個完全抽象的類,沒有提供任何實現。我們只能描述類應該像什麼,做什麼,但不能描述怎麼做,即只能決定方法名、引數列表和返回型別,但是無法確定方法體。介面只提供形式,通常來說沒有實現,儘管在某些受限制的情況下可以有實現。
Java 8 中介面稍微有些變化,因為 Java 8 允許介面包含預設方法和靜態方法——基於某些重要原因,看到後面你會理解。介面的基本概念仍然沒變,介於型別之上、實現之下。介面與抽象類最明顯的區別可能就是使用上的慣用方式。介面的典型使用是代表一個類的型別或一個形容詞,如 Runnable 或 Serializable,而抽象類通常是類層次結構的一部分或一件事物的型別,如 String 或 ActionHero。
介面同樣可以包含屬性,這些屬性被隱式指明為 static 和 final。
使用 implements 關鍵字使一個類遵循某個特定介面(或一組介面),它表示:介面只是外形,現在我要說明它是如何工作的。除
此之外,它看起來像繼承。
// interfaces/ImplementingAnInterface.java
interface Concept { // Package access
void idea1();
void idea2();
}
class Implementation implements Concept {
@Override
public void idea1() {
System.out.println("idea1");
}
@Override
public void idea2() {
System.out.println("idea2");
}
}
你可以選擇顯式地宣告介面中的方法為 public,但是即使你不這麼做,它們也是 public 的。所以當實現一個介面時,來自介面中的方法必須被定義為 public。否則,它們只有包訪問許可權,這樣在繼承時,它們的可訪問許可權就被降低了,這是 Java 編譯器所不允許的。
預設方法
在java8 中提供了一個 default 關鍵字,當在介面中使用它,相當於在介面中提供了一種預設方法,介面的實現中並不需要再定義此方法。
interface InterfaceWithDefault {
void firstMethod();
void secondMethod();
default void newMethod() {
System.out.println("newMethod");
}
}
public class Implementation2 implements InterfaceWithDefault {
@Override
public void firstMethod() {
System.out.println("firstMethod");
}
@Override
public void secondMethod() {
System.out.println("secondMethod")
}
public static void main(String[] args) {
InterfaceWithDefault i = new Implementation2();
i.firstMethod();
i.secondMethod();
i.newMethod();
}
}
就像這樣,輸出
firstMethod
secondMethod
newMethod
儘管 Implementation2 中未定義 newMethod(),但是可以使用 newMethod() 了。
增加預設方法的極具說服力的理由是它允許在不破壞已使用介面的程式碼的情況下,在介面中增加新的方法。預設方法有時也被稱為守衛方法或虛擬擴充套件方法。
抽象類 與 介面
在java8 引入 default 後 選擇用抽象類還是介面 變得令人困惑,下表給出區分。
特性 | 介面 | 抽象類 |
---|---|---|
組合 | 新類可以組合多個介面 | 只能繼承單一抽象類 |
狀態 | 不能包含屬性(除了靜態屬性,不支援物件狀態) | 可以包含屬性,非抽象方法可能引用這些屬性 |
預設方法 和 抽象方法 | 不需要在子類中實現預設方法。預設方法可以引用其他介面的方法 | 必須在子類中實現抽象方法 |
構造器 | 沒有構造器 | 可以有構造器 |
可見性 | 隱式 public | 可以是 protected 或 "friendly" |