更新時間:2022-11-28 10:21:11 來源:動力節點 瀏覽1378次
似乎抽象類和構造函數可能不兼容的。構造函數方法被稱為實例化一個類時,和一個抽象類不能實例化。
在本文中,我們將看到為什么抽象類可以有構造函數和如何使用它們在子類實例化提供了好處。
當一個類不申報任何構造函數,編譯器會創建一個默認的構造函數。這也適用于抽象類。即使沒有顯式的構造函數,抽象類有一個默認的構造函數。
在一個抽象類,它的后代可以使用超級調用抽象默認構造函數():
public abstract class AbstractClass {
// compiler creates a default constructor
}
public class ConcreteClass extends AbstractClass {
public ConcreteClass() {
super();
}
}
我們可以聲明一個構造函數沒有參數在一個抽象類。它會覆蓋默認的構造函數,以及任何子類創建將稱之為第一建設鏈。
讓我們驗證這一行為有兩個抽象類的子類:
public abstract class AbstractClass {
public AbstractClass() {
System.out.println("Initializing AbstractClass");
}
}
public class ConcreteClassA extends AbstractClass {
}
public class ConcreteClassB extends AbstractClass {
public ConcreteClassB() {
System.out.println("Initializing ConcreteClassB");
}
}
讓我們看看輸出得到當調用新的ConcreateClassA ():
初始化AbstractClass
而輸出調用新的ConcreteClassB()將會是:
初始化AbstractClass
初始化ConcreteClassB
(1)安全初始化
聲明一個抽象的不帶參數的構造函數可以有利于安全初始化。
以下計數器類計數自然數的超類。我們需要它的值從0開始。
讓我們來看看我們可以使用一個參數構造函數來確保安全的初始化:
public abstract class Counter {
int value;
public Counter() {
this.value = 0;
}
abstract int increment();
}
我們SimpleCounter子類實現增量和+ +運算符()方法。它由一個在每個增量的價值調用:
public class SimpleCounter extends Counter {
@Override
int increment() {
return ++value;
}
}
請注意,SimpleCounter不申報任何構造函數。成立依賴柜臺默認的無參數構造函數被調用。
下面的單元測試演示了安全屬性被初始化的值構造函數:
@Test
void givenNoArgAbstractConstructor_whenSubclassCreation_thenCalled() {
Counter counter = new SimpleCounter();
assertNotNull(counter);
assertEquals(0, counter.value);
}
(2)阻止訪問
計數器的初始化工作正常,但是讓我們想象我們不想讓子類覆蓋這個安全初始化。
首先,我們需要阻止子類的構造函數私有訪問:
private Counter() {
this.value = 0;
System.out.println("Counter No-Arguments constructor");
}
其次,讓我們創建另一個調用子類的構造函數:
public Counter(int value) {
this.value = value;
System.out.println("Parametrized Counter constructor");
}
最后,我們需要SimpleCounter覆蓋參數化構造函數,否則,它不會編譯:
public class SimpleCounter extends Counter {
public SimpleCounter(int value) {
super(value);
}
// concrete methods
}
注意編譯器預計我們稱之為超級構造函數(值),限制訪問我們的私人參數構造函數。
最常見的一種使用抽象類的構造函數是為了避免冗余。讓我們創建一個示例使用汽車,看看我們可以利用參數化構造函數。
我們從一個抽象的汽車類來代表所有類型的汽車。我們還需要知道多少旅行距離屬性:
public abstract class Car {
int distance;
public Car(int distance) {
this.distance = distance;
}
}
我們的超類看起來很好,但我們不希望距離屬性被初始化一個非零值。我們也要防止子類改變財產或覆蓋的距離參數化構造函數。
讓我們看一下如何限制距離和安全地使用構造函數來初始化:
public abstract class Car {
private int distance;
private Car(int distance) {
this.distance = distance;
}
public Car() {
this(0);
System.out.println("Car default constructor");
}
// getters
}
現在,我們距離屬性和參數化構造函數是私有的。有公共汽車默認構造函數()代表私有構造函數來初始化的距離。
財產使用我們的距離,讓我們添加一些行為來獲取和顯示汽車的基本信息:
abstract String getInformation();
protected void display() {
String info = new StringBuilder(getInformation())
.append("\nDistance: " + getDistance())
.toString();
System.out.println(info);
}
所有子類都需要提供一個實現getInformation(),和顯示()方法將使用它來打印所有的細節。
現在讓我們創建ElectricCar和FuelCar子類:
public class ElectricCar extends Car {
int chargingTime;
public ElectricCar(int chargingTime) {
this.chargingTime = chargingTime;
}
@Override
String getInformation() {
return new StringBuilder("Electric Car")
.append("\nCharging Time: " + chargingTime)
.toString();
}
}
public class FuelCar extends Car {
String fuel;
public FuelCar(String fuel) {
this.fuel = fuel;
}
@Override
String getInformation() {
return new StringBuilder("Fuel Car")
.append("\nFuel type: " + fuel)
.toString();
}
}
讓我們看看這些子類行動:
ElectricCar electricCar = new ElectricCar(8);
electricCar.display();
FuelCar fuelCar = new FuelCar("Gasoline");
fuelCar.display();
產生的輸出的樣子:
Car default constructor
Electric Car
Charging Time: 8
Distance: 0
Car default constructor
Fuel Car
Fuel type: Gasoline
Distance: 0
像任何其他類在Java中,抽象類可以有構造函數,即使他們只是從具體的子類。如果大家想了解更多相關知識,不妨來關注一下本站的Java基礎教程,里面還有更豐富的知識等著大家去學習,希望對大家能夠有所幫助哦。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習