2

ダウンキャストが実行できないことはわかっています。しかし、私はそれを回避しようとしています。

これは私が持っているものです。

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

public class MyTicket extends Ticket{
   public String status;
}

しかし、私のアプリでは、元の Ticket オブジェクトを強制的に変更したくないので、MyTicket クラスを使用したいと考えています。そのため、Ticket オブジェクトが呼び出し (Web サービス、DB など) から戻ってきたときに、MyTicket にダウンキャストしようとすると、明らかに失敗します。

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

だから私はこれを回避する方法を見つけようとしていました。「copyAttributes」メソッドを作成するか、MyTicket クラスのコンストラクター内で属性をコピーすることを考えていました。次のようなものです。

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
    }
}

クラスの属性を取得して別のクラスに設定する方法はありますか? または、ダウンキャストするまったく別の方法があり、私はそれを見逃していますか?

*解決策: *だから私は以下の解決策を取り、これを思いついた. 転送が行われる前にメイン チケットが見つからない場合に 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;
    }
}
4

7 に答える 7

2

ダウンキャストは、参照が実際にサブクラス型であることがわかっている場合にのみ使用してください。Web サービスによって返された Ticket オブジェクトは実際には MyTicket ではないようです。そのため、ClassCastException実行時にダウンキャストがスローされます。

MyTicket の構築中に Web サービスから返された Ticket を使用する場合は、Ticket オブジェクトを取得して属性をコピーするコピー コンストラクターを Ticket クラスに定義します。このコピー コンストラクターは、Ticket オブジェクトを受け取る MyTicket のコンストラクターで呼び出されます。

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;
   }
}
于 2012-10-12T14:58:22.640 に答える
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));
于 2012-10-12T15:03:38.377 に答える
1

あなたは正しいことをしていると思います。オブジェクトが大きくなった場合はApache BeanUtils、属性のコピーを支援するために を使用できます。

于 2012-10-12T14:54:05.993 に答える
0

冗長性が最も少ないコードを使用する最も良い方法は、事前に何もコピーせずに、元のインスタンス(集約)を含め、必要に応じてその属性をMyTicket使用することTicketです

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

ただし、ゲッターを介してすべてのプロパティを公開する必要がある場合、これはあまり役に立ちません。Ticket一部の計算で内部的にプロパティが必要な場合にのみ役立ちます。

于 2012-10-12T15:03:34.260 に答える
0

取得しているオブジェクトが MyTicket ではなく Ticket オブジェクトとして作成された場合、コピー コンストラクターで提案した方法でアプローチします。

于 2012-10-12T14:58:33.750 に答える
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
 }

私が見つけた良い例 (長いですが、長いものを読むのに問題はありません。あなたがプログラマーなら、そうすべきではありません。):

クラスとオブジェクトのレッスンで提示された Bicycle クラスの可能な実装のサンプル コードを次に示します。

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;
}

}

Bicycle のサブクラスである MountainBike クラスのクラス宣言は、次のようになります。

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;
}   
}

MountainBike は Bicycle のすべてのフィールドとメソッドを継承し、フィールド seatHeight とそれを設定するメソッドを追加します。コンストラクターを除いて、4 つのフィールドと 5 つのメソッドを持つ新しい MountainBike クラスをまったくゼロから作成したかのようです。ただし、すべての作業を行う必要はありませんでした。これは、Bicycle クラスのメソッドが複雑で、デバッグにかなりの時間がかかった場合に特に役立ちます。サブクラスでできること

サブクラスは、サブクラスが含まれているパッケージに関係なく、その親のすべてのパブリック メンバーと保護されたメンバーを継承します。サブクラスがその親と同じパッケージに含まれている場合、親のパッケージ プライベート メンバーも継承します。継承されたメンバーをそのまま使用したり、置き換えたり、非表示にしたり、新しいメンバーで補足したりできます。

継承されたフィールドは、他のフィールドと同様に直接使用できます。スーパークラスのフィールドと同じ名前のサブクラスのフィールドを宣言して、非表示にすることができます (推奨されません)。スーパークラスにはないサブクラスで新しいフィールドを宣言できます。継承されたメソッドはそのまま使用できます。スーパークラスのインスタンス メソッドと同じシグネチャを持つ新しいインスタンス メソッドをサブクラスに記述して、オーバーライドすることができます。スーパークラスと同じシグネチャを持つ新しい静的メソッドをサブクラスに記述して、それを隠すことができます。スーパークラスにはないサブクラスで新しいメソッドを宣言できます。暗黙的に、またはキーワード super を使用して、スーパークラスのコンストラクターを呼び出すサブクラス コンストラクターを作成できます。

このレッスンの次のセクションでは、これらのトピックについて詳しく説明します。スーパークラスのプライベート メンバー

サブクラスは、親クラスのプライベート メンバーを継承しません。ただし、スーパークラスにプライベート フィールドにアクセスするためのパブリック メソッドまたはプロテクト メソッドがある場合、これらはサブクラスでも使用できます。

ネストされたクラスは、それを囲むクラスのすべてのプライベート メンバー (フィールドとメソッドの両方) にアクセスできます。したがって、サブクラスによって継承されたパブリックまたは保護されたネストされたクラスは、スーパークラスのすべてのプライベート メンバーに間接的にアクセスできます。オブジェクトのキャスト

オブジェクトは、インスタンス化された元のクラスのデータ型であることがわかりました。たとえば、次のように書くと

public MountainBike myBike = new MountainBike();

myBike は MountainBike 型です。

MountainBike は Bicycle と Object の子孫です。したがって、MountainBike は Bicycle であり、Object でもあり、Bicycle または Object オブジェクトが必要な場所であればどこでも使用できます。

逆は必ずしも真ではありません。Bicycle は MountainBike である可能性がありますが、必ずしもそうとは限りません。同様に、オブジェクトは自転車またはマウンテン バイクである場合がありますが、必ずしもそうとは限りません。

キャストは、継承と実装によって許可されているオブジェクトの中で、ある型のオブジェクトを別の型の代わりに使用することを示しています。たとえば、次のように書くと

Object obj = new MountainBike();

その場合、obj はオブジェクトとマウンテンバイクの両方になります (obj がマウンテンバイクではない別のオブジェクトに割り当てられるまで)。これは、暗黙のキャストと呼ばれます。

一方、次のように書くと、

MountainBike myBike = obj;

コンパイラは obj が MountainBike であると認識していないため、コンパイル時にエラーが発生します。ただし、明示的なキャストによって MountainBike を obj に割り当てることを約束していることをコンパイラに伝えることができます。

MountainBike myBike = (MountainBike)obj;

このキャストは、コンパイラが obj が MountainBike であると安全に想定できるように、obj に MountainBike が割り当てられていることを確認する実行時チェックを挿入します。実行時に obj が Mountainbike でない場合、例外がスローされます。注: instanceof 演算子を使用して、特定のオブジェクトの型に関する論理テストを行うことができます。これにより、不適切なキャストによる実行時エラーを回避できます。例えば:

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

ここで、instanceof 演算子は、obj が MountainBike を参照していることを確認します。これにより、ランタイム例外がスローされないという知識でキャストを行うことができます。

TL;DR: 継承を使用すると、すべての正方形が長方形になりますが、すべての長方形が正方形になるわけではありません..

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

于 2012-10-12T14:54:13.657 に答える
0

Cloneableのようなものを実装することをお勧めします(ただし、標準の Java のものではありません。ここでは、スーパークラスに抽象メソッドを提供しても問題ない場合があります)。MyTicketクラスでは次のようになります。

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

private MyTicket(MyTicket t) {
}
于 2012-10-12T14:53:03.517 に答える