9

假设我有一个类层次结构如下:

class Vehicle;
class Car extends Vehicle;
class Plane extends Vehicle;

我有一个比较两个对象的函数

public <T extends Vehicle> generateDiff(T original, T copy)

在编译时,上面的方法保证两个对象是Vehicle,但不能保证两个对象的类型相同。

generateDiff(new Car(), new Car()); //OK
generateDiff(new Plane(), new Plane()); //OK
generateDiff(new Car(), new Plane()); //WRONG

我可以在编译时使用泛型实现这一点吗?

Ps:目前,我已经实现了如果Class两个对象不一样会抛出异常。但我对此并不满意。

提前致谢。

4

7 回答 7

8

是的,你可以(有点)!

类型T是从参数中推断出来的,但您可以指定类型:

MyClass.<Car>generateDiff(new Car(), new Plane()); // generates a compile error

如果不键入方法,则类型T被推断为满足所用边界的最窄类,因此对于参数CarPlane,最窄的类型是Vehicle,因此这两行是等价的:

generateDiff(new Car(), new Plane()); // type is inferred as Vehicle
MyClass.<Vehicle>generateDiff(new Car(), new Plane());

上面的代码假设generateDiff()是一个静态方法。如果它是一个实例方法,您可以键入您的类并在您的方法中使用该类型。

于 2012-06-19T04:52:33.837 回答
6

一旦你深入了解它,它就会变得有点抽象。您还必须为函数提供类类型(见下文)。如果您想强制执行此类行为,我建议您编写单独的方法来接受您希望比较的类型。反正:

public <C extends Vehicle> void generateDiff(Class<C> type, C original, C copy);

你可以这样使用它:

generateDiff(Plane.class, new Plane(), new Plane()); // OK
generateDiff(Car.class, new Car(), new Car()); // OK
generateDiff(Plane.class, new Plane(), new Car()); // ERROR
generateDiff(Vehicle.class, new Plane(), new Car()); // OK

不知道为什么任何理智的人会想要这样做!:)

于 2012-06-19T05:00:36.223 回答
3

在我看来,任何可以接受 Vehicle 作为参数的方法都不可能接受 CAR 和 PLANE。由于编译器不知道会出现什么样的对象(可以是 CAR、BUS、PLANE),所以它不能保证两个参数的类型完全相同。如果有人扩展CAR并创建福特?两个对象都是 CAR 类型。

确保这一点的唯一方法是在运行时使用自定义逻辑。

于 2012-06-19T04:46:47.633 回答
3

严格来说,您的问题的答案是“不,这是不可能的”。

但是,有一种解决方法。创建一个方法<T extends Vehicle> VehicleDiffer<T> compare(T vehicleA),其中VehicleDiffer<T>有一个方法ReturnType with(T vehicleB)。现在您可以执行以下调用:

compare(new Car()).with(new Car()); // okay
compare(new Plane()).with(new Plane()); // okay

以下将失败:

compare(new Car()).with(new Plane()); // with(Car) can't be called with argument type Plane
于 2012-06-19T06:20:04.280 回答
1

不,无论有没有泛型,这都无法实现。本质上,您是在询问是否可以告诉编译器违反多态性规则。

即使您明确定义了一个没有泛型的方法,如下面的方法,它仍然会接受任何一对扩展的类Vehicle

void generateDiff(Vehicle maybePlane, Vehicle maybeCar) { ...

有一种情况是例外,但我不建议这样做。如果您针对扩展的final类对象(或任何未扩展的类)调用该方法,则Vehicle可以覆盖该方法以匹配该类的每个参数的签名。但是您需要明确定义每一个。

class Vehicle;
final class Car extends Vehicle;
final class Plane extends Vehicle;

void generateDiff(Car car1, Car car2) { ...
void generateDiff(Plane plane1, Plane plane2) { ...

generateDiff(new Car(), new Car()); // OK
generateDiff(new Plane(), new Plane()); // OK
generateDiff(new Car(), new Plane()); // No matching method
于 2012-06-19T04:54:50.857 回答
1

我可以在编译时使用泛型实现这一点吗?

不,因为类型是在运行时设置的,但是如果将无效类型发送到函数,您可以简单地使用自省并抛出异常,但如果是这种情况,那么它们可能在您的设计中存在缺陷,但这只是我的意见.

instanceof运算符将检查底层类型,因此您可以引发异常或做一些更合适的事情。

public <T extends Vehicle> generateDiff(T original, T copy)

因为您可能正在比较不同的类型,也许您不应该有一个函数,因为它需要相当多if else的函数,在每个类中相应地实现函数可能更明智,这样它们就可以正确地与适当类型的对象进行比较,虽然我采取了相当数量的假设,这可能是错误的。

于 2012-06-19T04:55:21.513 回答
0

不,那是不可能的!

这就是我要做的:

class Vehicle;
class Car extends Vehicle;
class Plane extends Vehicle;

class DiffGenerator {
  public Diff generateDiff(Car original, Car copy) {
    return generateDiff(original, copy)
  }

  public Diff generateDiff(Plane original, Plane copy) {
    return generateDiff(original, copy)
  }

  private Diff generateDiff(Vehicle original, Vehicle copy) {
    return generatedDiff;
  }

}

注意到私有方法了吗?private Diff generateDiff(Vehicle original, Vehicle copy)

于 2012-06-19T05:03:43.997 回答