Ответ 1
Нет. Это не имело бы смысла, если бы все типы не имели пустой тип объединения, например. интерфейс, который они все реализовали, или базовый класс, который они все расширили, и в этом случае вы просто указываете тип объединения.
Есть ли синтаксис или обходной путь для ограничения параметра типового типа для любого из нескольких типов?
Я знаю, что вы можете ограничить тип всем диапазоном типов (т.е. AND
logic):
public class MyClass<T extends Comparable<T> & Serializable> { } // legal syntax
Существует ли логическая версия OR
, например:
public class MyClass<T extends Comparable<T> | Serializable> { } // illegal syntax
Если нет синтаксиса, который поддерживает это (я не думаю, что есть), есть ли способ обхода или подход, который является хорошим шаблоном?
В некоторых случаях одним из примеров использования может быть:
/** @return true if the obj is either has the same id, or if obj is the same as id */
public <T extends MyClass | String> boolean sameAs(T obj) {
if (obj instanceof String) return this.id.equals(obj);
if (obj instanceof MyClass) return this.id.equals(((MyClass)obj).id);
return false;
}
Люди, похоже, повесились на точной семантике моего метода, описанного выше. Попробуйте это вместо этого:
public class MyWrapper<T extends A | B> {
// my class can wrap A or B (unrelated classes). Yes I will probably use instanceof
}
Редакция:
Я не буду знать во время компиляции, которое я мог бы получить (исходя из внешнего кода), поэтому я хочу избежать создания конкретных классов для каждого типа. Кроме того, я должен отдать свой класс иностранной системе, которая вызывает мой класс .method, но другая система может предоставить мне экземпляры различных классов, но узко определенную и известную разновидность.
Некоторые люди прокомментировали, что instanceof
является "нечистым". Ну, одним из способов является использование метода factory для выбора моего конкретного класса на основе класса входящего объекта, но этот метод factory должен был бы использовать instanceof
, поэтому вы просто перемещаете instanceof
в другое место - вам все равно нужен instanceof
.
Или эта идея просто не всегда хороша?
Нет. Это не имело бы смысла, если бы все типы не имели пустой тип объединения, например. интерфейс, который они все реализовали, или базовый класс, который они все расширили, и в этом случае вы просто указываете тип объединения.
public class MyWrapper<T extends A | B> {}
Вы не можете сделать это для интерфейсов, на которые у вас нет контроля, но для собственных вещей вы можете использовать пустой интерфейс маркера:
interface AOrB {
}
interface A extends AOrB {
someMethodHere();
}
interface B extends AOrB {
someOtherMethodHere();
}
public class MyClass<T extends AOrB> {}
Независимо от того, что говорят пуристы, использование instanceof
отлично, когда вам это нужно.
В то время как Java имеет ограниченную поддержку " типы пересечений" как T1 & T2
, поддержка "типов объединения" скудна.
Общие типы с подстановочными символами являются фактически типами объединения: G<? extends X>
является объединением всех G<S>
, где S
является подтипом X
.
Нет поддержки объединения произвольных двух типов.
Синтаксис с несколькими лотками Java 7 выглядит так, будто он поддерживает объединение произвольных типов исключений
catch (IOException|SQLException ex){ .. }
но на самом деле тип ex
является фиксированным суперклассом, а не объединением двух классов.
Использование instanceof
считается не очень хорошим стилем программирования и позволяет использовать OR
в дженериках, что вы будете использовать его.
Следующий код будет делать то же самое, что и в приведенном примере, но без проверки типа исполнения и типов.
public boolean sameAs(MyClass obj) {
return this.id.equals(obj.id);
}
public boolean sameAs(String obj) {
return this.id.equals(obj);
}
Проверка NPE может быть хорошей идеей.