2

我知道向下转换是不可行的。但我正在努力解决它。

这就是我所拥有的。

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

public class MyTicket extends Ticket{
   public String status;
}

但是在我的应用程序中,我想使用 MyTicket 类,因为我不想强制更改原始 Ticket 对象。因此,当 Ticket 对象从调用(webservice、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 类中定义一个复制构造函数,它将获取一个票证对象并复制属性。此复制构造函数将在 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;
   }
}
于 2012-10-12T14:58:22.640 回答
1

我认为你做得对。如果您的对象增长,您可能希望使用它Apache BeanUtils来帮助您进行属性复制。

于 2012-10-12T14:54:05.993 回答
1

在这种情况下,为什么不直接使用聚合 + getter/setter?

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 回答
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 回答
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 和设置它的方法。除了构造函数之外,就好像您完全从头开始编写了一个新的 MountainBike 类,有四个字段和五个方法。但是,您不必完成所有工作。如果 Bicycle 类中的方法很复杂并且需要大量时间来调试,这将特别有价值。你可以在子类中做什么

子类继承其父类的所有公共和受保护成员,无论子类在哪个包中。如果子类与其父类在同一个包中,它也继承父类的包私有成员。您可以按原样使用继承的成员、替换它们、隐藏它们或用新成员补充它们:

继承的字段可以直接使用,就像任何其他字段一样。您可以在子类中声明一个与超类中同名的字段,从而隐藏它(不推荐)。您可以在子类中声明不在超类中的新字段。继承的方法可以直接使用。您可以在子类中编写一个与超类具有相同签名的新实例方法,从而覆盖它。您可以在子类中编写一个与超类具有相同签名的新静态方法,从而隐藏它。您可以在子类中声明不在超类中的新方法。您可以编写一个子类构造函数来调用超类的构造函数,或者隐式调用,或者使用关键字 super。

本课的以下部分将扩展这些主题。超类中的私有成员

子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。

嵌套类可以访问其封闭类的所有私有成员——包括字段和方法。因此,子类继承的公共或受保护的嵌套类可以间接访问超类的所有私有成员。铸造对象

我们已经看到,一个对象的数据类型与实例化它的类相同。例如,如果我们写

public MountainBike myBike = new MountainBike();

那么 myBike 是 MountainBike 类型。

MountainBike 是 Bicycle 和 Object 的后代。因此,MountainBike 是 Bicycle,也是 Object,可以在需要 Bicycle 或 Object 对象的任何地方使用。

反过来不一定正确:自行车可能是山地自行车,但不一定。同样,Object 可能是 Bicycle 或 MountainBike,但不一定。

转换显示了在继承和实现允许的对象中使用一种类型的对象代替另一种类型的对象。例如,如果我们写

Object obj = new MountainBike();

那么 obj 既是 Object 又是 Mountainbike(直到 obj 被分配另一个不是 Mountainbike 的对象)。这称为隐式转换。

另一方面,如果我们写

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

如果您要返回的对象是作为 Ticket 对象而不是 MyTicket 创建的,那么我将按照您使用复制构造函数提出的方式来处理它。

于 2012-10-12T14:58:33.750 回答
0

最好的方法是使用最少的冗余代码,让您MyTicket包含原始实例Ticket聚合)并在需要时使用其属性,而无需提前复制任何内容。

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

如果您需要通过 getter 公开所有属性,那么这将没有多大用处。Ticket仅当您在内部需要 s 属性进行某些计算时,它才会有所帮助。

于 2012-10-12T15:03:34.260 回答