首页 > 解决方案 > 使用泛型作为返回类型参数 Java

问题描述

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

我有一个扩展抽象类 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 时,此方法返回给我一个对象,而我只有方法 toString 可用。

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

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

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

谢谢,

标签: javagenerics

解决方案


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

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

它返回Object是因为在没有您指定类型的情况下,类型参数T会被推断为Object,因为T仅以 为界Object

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

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

这将编译,但当你运行它时会崩溃。

这是因为您声明receiveHiredObject返回一个T- 泛型参数。这意味着T调用者指定的任何内容 - 无论是VehicleHotel还是Foo,receiveHiredObject都被声明为返回该类型的事物。显然,它不会那样做。它返回的内容取决于使用的子类。调用者无法决定它返回什么!当您实现receiveHiredObjectin 时VehicleOrder,您会收到警告,因为返回的 aVehicle可能不是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?

推荐阅读