Как сказать компилятору, что два объекта одного и того же - но неизвестного - класса (с обобщениями)?
Пожалуйста, рассмотрите следующий код:
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>
имеет "удобную" функцию, просто сравнивая 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, с очень минимально выразительной системой типов.
Еще одна альтернативная реализация:
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;
Вы можете работать таким образом.