Как сказать компилятору, что два объекта одного и того же - но неизвестного - класса (с обобщениями)?

Пожалуйста, рассмотрите следующий код:

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>
  }

}

Код работает (учитывая классы Cat а также Apple) но компилятор предупреждает о небезопасных операциях, потому что я использую compareTo без дженериков. Однако я не знаю, как это исправить, потому что понятия не имею, как это указать. c1 а также c2 одного типа, но неизвестного типа (в if пункт). Есть ли способ (кроме использования @SuppressWarnings конечно) чтобы это исправить?

Я знаю, что здесь есть похожий вопрос: как сказать Java, что два подстановочных знака совпадают? Но ответ, данный там, кажется, специфичен для контекста спрашивающего. Например, он использует карту ключ-значение, которой нет в моем контексте.

5 ответов

Поскольку состояние 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> имеет "удобную" функцию, просто сравнивая Ts. И теперь мы за это платим.

За .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, с очень минимально выразительной системой типов.

Еще одна альтернативная реализация:

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;
  }

Обновите свои методы, чтобы иметь дело с 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>
  }

}

Вы можете использовать операторы instanceof. Вы можете написать это как:

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





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

Вы можете работать таким образом.

Другие вопросы по тегам