如何告诉编译器两个对象属于相同但未知的类(带有泛型)



请考虑以下代码:

public class MyClass {
  public static void main(String[] args) {    
    Object o1 = getObject(Math.random());
    Object o2 = getObject(Math.random());
    if (o1.getClass().equals(o2.getClass()) { // two Cars or two Apples
      Comparable c1 = (Comparable) o1;
      Comparable c2 = (Comparable) o2;
      int x = c1.compareTo(c2); // unsafe
      System.out.println(x);
    )
  }
  public Object getObject(double d) { // given method that may not be changed
    if (d < 0.5) return (new Car()); // Car implements Comparable<Car>
    else return (new Apple()); // Apple implements Comparable<Apple>
  }
}

代码有效(给定类 CatApple ),但编译器警告不安全的操作,因为我使用没有泛型的compareTo。但是,我不知道如何解决此问题,因为我不知道如何指定c1c2属于相同但未知的类型(在if子句中)。有没有办法(当然除了使用@SuppressWarnings)来解决这个问题?

我知道这里有一个类似的问题:如何告诉 Java 两种通配符类型是相同的?但那里给出的答案似乎特定于提问者的上下文。例如,它使用在我的上下文中不存在的键值映射。

由于条件if (o1.getClass().equals(o2.getClass()))保证两个对象属于同一类,忽略警告是安全的。您可以抑制它。

但是,由于此时它们的类型Object,将它们投到Comparable是不安全的.您可以通过一些小的调整使其更安全,使它们具有类Comparable

public static void main(String[] args) {
    Comparable<?> o1 = getComparable(Math.random());
    Comparable<?> o2 = getComparable(Math.random());
    if (o1.getClass().equals(o2.getClass())) {
        // safe cast
        Comparable c1 = (Comparable) o1;
        Comparable c2 = (Comparable) o2;
        // safe comparison
        int x = c1.compareTo(c2);
        System.out.println(x);
    }
}
public Comparable<? extends Comparable<?>> getComparable(double d) {
    if (d < 0.5) return (new Car());
    return (new Apple());
}

这里的问题是Comparable<Car>Comparable<Apple>不能相互比较,因为Comparable<T>具有"舒适"功能,只需比较T s。现在我们正在为此付出代价。

对于.equals来说,情况并非如此。

我们正在尝试什么

// WILL NOT WORK
if (o1.getClass().equals(o2.getClass()) { // two Cars or two Apples
  int x = comparison(o1.getClass(), o1, o2);
  System.out.println(x);
)
static <T extends Comparable<T>> int comparison(Class<T> type, T o1, T o2) {
    return type.cast(o1).compareTo(type.cast(o2));
}

这是Java的一个特性,具有非常少的表现力类型系统。

更新方法以处理Comparable对象而不是Object对象。

public class MyClass {
  public static void main(String[] args) {    
    Comparable o1 = getObject(Math.random());
    Comparable o2 = getObject(Math.random());
    if (o1.getClass().equals(o2.getClass()) { // two Cars or two Apples
      int x = o1.compareTo(o2);
      System.out.println(x);
    )
  }
  public Comparable getObject(double d) { // given method that may not be changed
    if (d < 0.5) return (new Car()); // Car implements Comparable<Car>
    else return (new Apple()); // Apple implements Comparable<Apple>
  }
}

另一种替代实现:

public static void main(String[] args) {    
    Object o1 = getObject(Math.random());
    Object o2 = getObject(Math.random());
    if ( o1.getClass().equals(o2.getClass() ) && o1 instanceof Comparable ) {
      int x = getObject(o1).compareTo(o2);
      System.out.println(x);
    }
  }
  public static Object getObject(double d) { // given method that may not be changed
    if (d < 0.5) return ( new Car() ); // Car implements Comparable<Car>
    else return ( new Apple() ); // Apple implements Comparable<Apple>
  }
  public static <T> Comparable<T> getObject(Object o) {
      return (Comparable<T>)o;
  }

您可以使用 instanceof 运算符。您可以将其写为:

if(c1 instanceof Integer && c2 instanceof Integer)
   int x = c.compareTo(c2);


or if(c1 instanceof String)
    String s = c1;

你可以这样工作。

最新更新