【问题标题】:Using Generics for return type parameter Java使用泛型作为返回类型参数 Java
【发布时间】:2021-12-13 01:55:11
【问题描述】:

我正在尝试创建一个返回泛型类型参数的方法。

我有一个扩展抽象类 Order 的 VehicleOrder 类。 在 Order 类中,我创建了一个抽象方法 receiveHiredObject。这个方法不会接收任何参数,会返回一个泛型。

public abstract class Order implements Orderable {

private Date date;
private Customer customer;

public abstract <T> T receiveHiredObject();

我在类 VehicleOrder 中实现了这个方法,并设置它返回类参数车辆。

public class VehicleOrder extends Order {

private Vehicle vehicle;

public VehicleOrder(final Date date, final Customer customer, final Vehicle vehicle) {
    super(date, customer);
    this.vehicle = vehicle;
}

@SuppressWarnings("unchecked")
@Override
public Vehicle receiveHiredObject() {
    return vehicle;
}

问题是,当我实例化一个 Order 类型的新 VehilceOrder 并且使用方法 receiveHiredObject 时,此方法返回给我一个 Object,而我只有 toString 方法可用。

Order a = new VehicleOrder();
a.receiveHiredObject();

我希望将来对其他类型的对象(例如 HotelOrder)使用相同的方法。

我做错了什么,为什么方法 receiveHiredObject 返回的是 Object 而不是 VehicleOrder?如何改进返回正确类型的方法?

谢谢,

【问题讨论】:

  • 你能让Order类通用,并有VehicleOrder extends Order&lt;Vehicle&gt;吗?

标签: java generics


【解决方案1】:

注意receiveHiredObject 确实“返回正确的类型”,如果你告诉它要返回什么类型。

Order order = new VehicleOrder();
Vehicle v = order.receiveHiredObject();

它返回Object,因为如果不指定类型,类型参数T 会被推断为Object,因为T 仅受Object 的限制。

然而,你的方法根本不安全!你可以做一些愚蠢的事情,比如:

Order order = new VehicleOrder();
Hotel h = order.receiveHiredObject();

这会编译,但运行时会崩溃。

这是因为您声明 receiveHiredObject 以返回 T - 通用参数。这意味着无论调用者指定的TVehicleHotel 还是FooreceiveHiredObject 都被声明为返回该类型的事物。显然,它不会那样做。它返回的内容取决于使用的子类。调用者无法决定它返回什么!当您在 VehicleOrder 中实现 receiveHiredObject 时,您会收到一条警告,因为返回的 Vehicle 可能不是调用者所期望的 T,并且运行时无法为您检查这一点,但您抑制了警告。

所以receiveHiredObject 根本不应该是通用的。您可以改为使 Order 通用:

// might have to change Orderable too, if receiveHiredObject comes from there
public abstract class Order<T> implements Orderable {

    private Date date;
    private Customer customer;

    public abstract T receiveHiredObject();
}

public class VehicleOrder extends Order<Vehicle> {
    // same code as before...
}

现在调用者可以做:

Order<Vehicle> order = new VehicleOrder();
order.receiveHiredObject().someVehicleSpecificThing();

现在更安全了 - 您将无法从车辆订单中获得酒店。

请注意,绝对有必要提供Vehicle 的类型信息。这是因为order.receiveHiredObject 返回的内容由order 的运行时类型决定,而编译器 无法知道它是什么。在极端情况下思考:

Order order = new Random().nextBoolean() ? new VehicleOrder() : new HotelOrder();
// what type should order.receiveHiredObject return here?

【讨论】:

  • 嘿,谢谢你的解释,现在一切都清楚了。 :)
【解决方案2】:

例如,您可以将泛型类型声明移至类级别:

public abstract class Order<T> implements Orderable {
    private Date date;
    private Customer customer;

    public abstract T receiveHiredObject();
}

public class VehicleOrder extends Order<Vehicle> {

    private Vehicle vehicle;

    public VehicleOrder(final Date date, final Customer customer, final Vehicle vehicle) {
        super(date, customer);
        this.vehicle = vehicle;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Vehicle receiveHiredObject() {
         return vehicle;
    }
}

(认为语法正确)

【讨论】:

  • 优点:可以删除 SuppressWarnings。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-18
  • 2016-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多