2012-10-12 94 views
1

我知道向下轉換不可行。但我正在努力解決它。強制向下轉換

這就是我所擁有的。

public class Ticket{ 
    public int number; 
    public String description; 
} 

public class MyTicket extends Ticket{ 
    public String status; 
} 

但在我的應用程序,我想用MyTicket類,因爲我不想強迫原始票據對象改變。所以當Ticket對象從一個調用(web服務,數據庫等)返回時,我試圖向下轉換到一個MyTicket,它顯然失敗了。

MyTicket mt=(MyTicket)ws.getTicket(1234); 

所以我試圖找到解決這個問題的方法。我是在MyTicket類的構造函數中的思維寫「copyAttributes」方法的或複製的屬性,像這樣:

MyTicket mt=new MyTicket(ws.getTicket(1234)); 

public class MyTicket extends Ticket { 
    public String status; 
    public MyTicket(Ticket tckt){ 
     //copy tckt attributes to MyTicket attributes 
    } 
} 

有沒有辦法得到一個類的屬性,並將其設置到另一個類? 還是有一種完全不同的方式沮喪,我很想念它?

* SOLUTION: *所以我採取了下面的解決方案,並提出了這一點。我需要返回null變化,如果主票未發現轉移發生前:

public class MyTicket extends Ticket { 
    public String status; 
    public MyTicket(){} 
    public static MyTicket newInstance(Ticket tckt){ 
     MyTicket mytkt=null; 
     if(tckt!=null){//copy tckt attributes to MyTicket attributes 
      BeanUtilsBean.getInstance().getConvertUtils().register(false,true,-1); 
      mytkt = new MyTicket(); 
      BeanUtils.copyProperties(mytkt, tckt); 
     } 
     return mytkt; 
    } 
} 
+0

+1。缺乏隱式複製構造函數,甚至缺乏創建複製構造函數的文化,對於從C++進入Java的人來說通常是一個混亂點。 – ruakh

回答

1

我認爲你正在做正確的。如果您的對象增長,您可能需要使用Apache BeanUtils來協助您進行attrbute複製。

+0

我看到了這個。我正在嘗試使用它。但是如果一個對象爲空,它似乎會引發錯誤,尤其是Date對象。 – ovaherenow

+0

**這提供了不拋出異常的支持。**請參考我的回答關於相同的[註冊日期不要拋出異常](http://stackoverflow.com/questions/12719645/beanutils-copy-properties - 登記 - convertutils/12719908#12719908)。 –

+0

如果您認爲這有幫助,請不要忘記接受答案。 –

0

我建議你實現像一個Cloneable的(而不是標準的Java之一,這裏可能可以在你的超類中提供一個抽象方法)接口。像這樣的事情在MyTicket類:

@Override 
public Ticket clone() { 
    // copying stuff by calling a "copy constructor" 
    return new MyTicket(this); 
} 

private MyTicket(MyTicket t) { 
} 
+0

這沒有幫助。 OP希望將「Ticket」實例強制轉換爲「MyTicket」實例。 –

+0

哦,是的。有錯誤的問題。 – Markus

0

繼承:

public class ThisIsASubClass extends ThisIsASuperClass{ 
{ 
    //declare stuff here 
    Object o = "Let's presume a string is passed"; 
    super(o); //runs the super class (ThisIsASuperClass in this case), sending an object if needed (effectivly running the super class inside of the subclass) 
    //put the subclass code here 
} 

一個很好的例子,我發現(這是很長,但我沒有問題,閱讀長的事情,如果你是一個程序員,你也不應該。):

這裏爲可能的實現的自行車類的這是在類呈現和對象的代碼示例課:

public class Bicycle { 

// the Bicycle class has 
// three fields 
public int cadence; 
public int gear; 
public int speed; 

// the Bicycle class has 
// one constructor 
public Bicycle(int startCadence, int startSpeed, int startGear) { 
    gear = startGear; 
    cadence = startCadence; 
    speed = startSpeed; 
} 

// the Bicycle class has 
// four methods 
public void setCadence(int newValue) { 
    cadence = newValue; 
} 

public void setGear(int newValue) { 
    gear = newValue; 
} 

public void applyBrake(int decrement) { 
    speed -= decrement; 
} 

public void speedUp(int increment) { 
    speed += increment; 
} 

} 

類聲明用於山地車類,它是一個子類自行車的可能是這樣的:

public class MountainBike extends Bicycle { 

    // the MountainBike subclass adds 
    // one field 
    public int seatHeight; 

    // the MountainBike subclass has one 
    // constructor 
    public MountainBike(int startHeight, 
        int startCadence, 
        int startSpeed, 
        int startGear) { 
    super(startCadence, startSpeed, startGear); 
    seatHeight = startHeight; 
} 

// the MountainBike subclass adds 
// one method 
public void setHeight(int newValue) { 
    seatHeight = newValue; 
} 
} 

山地車繼承所有字段和自行車的方法,並增加了現場seatHeight並設置它的方法。除了構造函數外,就好像你已經從零開始寫了一個新的MountainBike類,有四個字段和五個方法。但是,您不必完成所有的工作。如果Bicycle類中的方法很複雜並花費大量時間進行調試,這將會特別有用。 你可以在子類中做什麼

子類繼承其父類的所有公共和受保護成員,不管子類是什麼包。如果子類與其父類位於同一個包中,它也繼承父級的包 - 私有成員。您可以按原樣使用繼承的成員,替換它們,隱藏它們或用新成員補充它們:

繼承的字段可以像任何其他字段一樣直接使用。 您可以在子類中聲明一個與超類中的名稱相同的字段,從而隱藏它(不推薦)。 您可以在子類中聲明不在超類中的新字段。 繼承的方法可以直接使用。 您可以在與超類中籤名相同的子類中編寫新的實例方法,從而覆蓋它。 您可以在與超類中籤名相同的子類中編寫一個新的靜態方法,從而隱藏它。 您可以在子類中聲明不在超類中的新方法。 您可以編寫一個調用超類的構造函數的子類構造函數,可以隱式地使用或使用關鍵字super。

本課的以下部分將詳細介紹這些主題。 超類中的私有成員

子類不繼承其父類的私有成員。但是,如果超類具有訪問其專用字段的公共或受保護方法,那麼這些也可以由子類使用。

嵌套類可以訪問其封閉類的所有私有成員,包括字段和方法。因此,由子類繼承的公共或受保護的嵌套類可間接訪問超類的所有私有成員。 Casting Objects

我們已經看到,一個對象是從中實例化的類的數據類型。例如,如果我們寫

public MountainBike myBike = new MountainBike(); 

那麼myBike是MountainBike的類型。

MountainBike是後代從Bicycle和Object。因此,一輛MountainBike是一輛自行車,同時也是一個對象,它可以用於要求Bicycle或Object對象的任何地方。

反過來並不一定是正確的:一輛自行車可能是一輛山地自行車,但並不一定。同樣,一個對象可能是一輛自行車或一輛山地自行車,但並不一定。

在繼承和實現允許的對象中,Casting顯示使用一種類型的對象代替另一種類型的對象。例如,如果我們寫

Object obj = new MountainBike(); 

然後obj是既一個對象和一個山地(直到與obj分配另一個目的爲不是這樣山地時間)。這被稱爲隱式投射。

如果,另一方面,我們寫

MountainBike myBike = obj; 

因爲obj是不知道的編譯器是山地車,我們會得到一個編譯時錯誤。但是,我們可以告訴編譯器,我們承諾分配山地車顯式鑄造OBJ:

MountainBike myBike = (MountainBike)obj; 

該投插入obj是否被分配了一個山地車,以便編譯器可以安全地假設obj是一個運行時檢查山地自行車。如果obj在運行時不是Mountainbike,則會拋出異常。 注意:您可以使用instanceof運算符對特定對象的類型進行邏輯測試。這可以幫助您避免由於不正確的轉換造成的運行時錯誤。例如:

if (obj instanceof MountainBike) { 
    MountainBike myBike = (MountainBike)obj; 
} 

這裏instanceof運算符驗證OBJ指的是山地車,使我們可以與知識會有不拋出運行時異常的演員。

TL; DR:如果您使用繼承,任何廣場是一個矩形,但不是所有的矩形爲正方形..

http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

+0

這些來自2個不同的問題,提供的鏈接 – Azulflame

+0

這個問題不是關於向下轉換(OP使用的術語錯誤),而第二種解決方案不適用,因爲OP從Web服務調用中檢索「Ticket」。 –

+0

好吧,如果不適用,我會刪除第二個。另外,如果他要求答案A並且想要答案B,他將得到答案A. – Azulflame

0

Downcasting應該當你知道引用是實際上是僅用於子類型。看來Web服務返回的Ticket對象實際上並不是MyTicket,因此向下轉換會在運行時拋出ClassCastException

即將使用在構建MyTicket時由Web服務返回的Ticket,我將在Ticket類中定義一個複製構造函數,該構造函數將獲取一個工單對象並複製這些屬性。此複製構造函數將在MyTicket的構造函數中調用,該構造函數接受一個Ticket對象。

public class Ticket{ 
    public int number; 
    public String description; 

    public Ticket(Ticket ticket) 
    { 
     this.number = ticket.number; 
     this.description = ticket.description; 
    } 
} 

public class MyTicket extends Ticket{ 
    public String status; 

    public MyTicket(Ticket ticket) 
    { 
     super(ticket); 
    } 

    public MyTicket(Ticket ticket, String status) 
    { 
     super(ticket); 
     this.status = status; 
    } 
} 
+0

我喜歡這個想法。我想這樣做。但是,我是否必須硬編碼超級類的副本中的每個屬性?我想使它通用,這就是我卡住的地方。 – ovaherenow

0

如果您在找回的對象是作爲票據對象創建不是MyTicket那麼我會接近它,你已經提出了拷貝構造函數的方式。

0

的最好的方式,用最少的冗餘代碼,將是您的MyTicket包含Ticket實例(聚集),並使用在需要它的屬性,而無需事先複製任何東西。

public class MyTicket extends Ticket { 
    private final Ticket t; 
    public MyTicket(Ticket t) { 
    this.t = t; 
    } 
} 

如果您需要通過getters公開所有屬性,那麼這將不會有太大用處。只有在內部需要Ticket的屬性才能進行某些計算時,這隻會有所幫助。

1

爲什麼不在這種情況下使用聚合+獲取/設置?

public class MyTicket { 
    private Ticket ticket; 
    private String status; 

    public MyTicket(Ticket ticket) { 
    this.ticket = ticket; 
    } 

    public int getNumber() { return ticket.number; } 
    public void setNumber(int number) { ticket.number = number; } 
    public String getDescription { return ticket.description; } 
    public void setDescription { ticket.description = description; } 
    public String getStatus() { return status; } 
    public void setStatus(String status) { this.status = status; } 
} 

然後,您可以創建你的對象,就像你的建議:

MyTicket mt = new MyTicket(ws.getTicket(1234)); 
+0

如果所有的房產都需要這樣暴露,那麼它的好處不大。更冗餘的代碼。 –

+0

這會將超類作爲子類的屬性。我寧願不這樣做。 – ovaherenow