[英]Java constructor of an abstract class
據我所知(如果我錯了請糾正我)一個抽象的類無法實例化。 你可以給它一個構造函數,但不能在該類上調用new。 如果在子類中調用super,超類構造函數將運行(從而創建該類的對象?)那么為什么你實際上可以在抽象類的子類中調用super? 我確定這與我對構造函數制作對象的誤解有關...
如果在子類中調用super,超類構造函數將運行(從而創建該類的對象??)那么為什么你可以在抽象類的子類中精確地調用super?
這部分是錯的。 當你在子類構造函數中調用super
時,你只是告訴子類它首先必須從超類(抽象與否)執行初始化代碼,然后它將繼續執行代碼來初始化當前的實例。正在創建的課程。 這並不意味着它將在創建當前實例的過程中創建超類的實例。
在抽象類中調用構造函數只能用於設置特定於該抽象類的屬性 - 否則在抽象類的每個實現中設置都會很繁瑣。 此功能可刪除鍋爐板代碼。
在下面的示例中,了解如何根據汽車的其他屬性計算汽車的使用壽命。 這在Car
子類型的每個實現中都是過多的。
abstract class Car {
// Determine how many years a car will last based on other components
int lifeTimeInYears;
float price;
public Car(float price) {
// Assuming you could calculate the longevity based on price;
if (price > 50000) {
lifeTimeInYears = 15;
}
else {
lifeTimeInYears = 10;
}
}
public int getLifeTimeInYears() {
return lifeTimeInYears;
}
}
class SportsCar extends Car {
public SportsCar(float price) {
super(price);
}
}
class CommuterCar extends Car {
public CommuterCar(float price) {
super(price);
}
}
public class Test {
public static void main(String[] args) {
SportsCar sportsCar = new SportsCar(150000);
sportsCar.getLifeTimeInYears(); // Value is 15
CommuterCar commuterCar = new CommuterCar(15000);
commuterCar.getLifeTimeInYears(); // Value is 10
}
}
讓我們說例如我們定義抽象類“汽車”。 然后我們寫了一個子類,“honda”擴展“car”。 為了制造“本田”,你必須先制作一輛“汽車”。 無論“car”是否是抽象的,為了制作任何子類對象,你必須首先調用super()來“make”超類對象。
在這里查看我對類似問題的回答: 當父類似乎沒有改變任何屬性時,是什么(有沒有?)一個目的,然后兩次聲明一個方法? (請注意,這個問題用詞不當,實際上是在討論構造函數)
我將嘗試在字節代碼級別解釋它,看看是否有幫助。
AbstractService.java
public abstract class AbstractService {
protected int id = 10;
public abstract void verify();
}
Service.java
public class Service extends AbstractService{
public static void main(String[] args) {
Service service = new Service();
service.verify();
}
public void verify() {
System.out.println("printing id = "+id);
}
}
如果查看這些類的生成字節代碼
public abstract class AbstractService {
protected int id;
public AbstractService() {
/* L4 */
0 aload_0; /* this */
1 invokespecial 1; /* java.lang.Object() */
/* L6 */
4 aload_0; /* this */
5 bipush 10;
7 putfield 2; /* .id */
10 return;
}
public abstract void verify();
}
public class Service extends com.sample.service.AbstractService {
public Service() {
/* L3 */
0 aload_0; /* this */
1 invokespecial 1; /* com.sample.service.AbstractService() */
4 return;
}
public static void main(java.lang.String[] args) {
/* L6 */
0 new 2;
3 dup;
4 invokespecial 3; /* com.sample.service.Service() */
7 astore_1; /* service */
/* L7 */
8 aload_1; /* service */
9 invokevirtual 4; /* void verify() */
/* L8 */
12 return;
}
public void verify() {
/* Skipping this as it's not needed */
}
}
Service service = new Service();
被翻譯成
0 new 2;
3 dup;
4 invokespecial 3; /* com.sample.service.Service() */
如上所示,首先執行新的字節代碼,它將創建一個新的Object,只有實例變量的默認值(在這種情況下,id是整數,所以默認為0)但是已經初始化,然后是dup,它將創建這個新的副本對象引用然后invokespecial將調用Service(),它將依次調用AbstractService()調用Object()
如果查看這些方法中的字節代碼,它們不會創建對象(沒有新的字節代碼指令),它們只是初始化對象,例如設置變量id = 10的值,這是對用戶定義值的正確初始化。
因此,當您說新的SomeClass()時,它不僅僅是調用您的構造函數,而是創建一個具有默認狀態的對象,然后調用名為constructor的特殊方法(編譯器生成一個或用戶定義的一個)來初始化該對象。 換句話說,構造函數將對象從默認狀態(id = 0)帶到用戶定義的狀態(id = 10),以便對象可以使用,即調用它的方法。
這在初學者級別太多但是如果你注意字節代碼它會有意義:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.