#java #types #set #type-safety
#java #типы #set #безопасность типов
Вопрос:
Мне нужен набор, который содержит только один тип данных и не разрешает добавлять в Набор ни один из его суперклассов или подклассов.
Ответ №1:
вы можете использовать Object.getClass()
для определения типа ваших объектов.
если вам нужна гарантия того, что добавляются только классы типа MyClass, вы могли бы просто расширить HashSet и переопределить add(Object o)
метод и добавить только элемент в коллекцию if (o.getClass() == MyClass.class)
:
Обновление: добавлен рабочий пример, который вы можете запускать как PoC.
public class MySet extends HashSet<MySet.MyClass> {
public static class MyClass {}
public static class MySubClass extends MyClass {}
@Override
public boolean add(MyClass c) {
if (c.getClass() != MyClass.class) {
throw new IllegalArgumentException("illegal class to add " c.getClass().getName());
}
return super.add(c);
}
public static void main(String[] args) {
MySet set = new MySet();
set.add(new MyClass()); // works
set.add(new MySubClass()); // throws Exception
}
}
выполнение этого примера дает:
Исключение в потоке «main» java.lang.Исключение IllegalArgumentException: недопустимый класс для добавления MySet$MySubClass
Комментарии:
1. Я не думаю, что это сработает, поскольку вы не можете переопределить
add()
и изменить тип его параметров одновременно. Возможно, вы имели в видуadd(object e)
вместо этого.2. этот пример работает вы можете добавить метод main и использовать
HashSet<String>
иgetClass()!=String.class
. я проверил это.3. @Peter: также типом аргумента add() является общий тип E из
HashSet<E>
->add(E o)
поэтомуHashSet<MyClass>
имеетadd(MyClass o)
: download.oracle.com/javase/1,5.0/docs/api/java/util/…4. Вы правы, я думал о таких методах, как
remove(Object)
иcontains(Object)
Ответ №2:
Хорошо, я думаю, что я совершенно неправильно понял суть.
Я бы, вероятно, использовал композицию, а не наследование, делегируя HashSet<T>
внутренне, но в add
вы бы хотели проверить:
if (o.getClass() != clazz)
{
// throw or reject
}
Обратите внимание, что это означает, что вам понадобится фактический класс во время выполнения, поэтому вам нужно будет создать набор с чем-то вроде:
ExactTypeSet<String> x = new ExactTypeSet<String>(String.class);
Ответ №3:
В очень специализированном случае, когда вы знаете тип класса, который хотите добавить, вы могли бы расширить существующую реализацию Set и переопределить add(Object o)
метод, разрешив добавлять объекты только там, где o.getClass().getName().equals("yourclassname")
.
Комментарии:
1. Проверка фактического класса была бы проще. Возможно иметь два класса в разных загрузчиках классов с одинаковым именем. (Я склонен находить это сбивающим с толку и избегать этого;)
2. Вы не должны сравнивать имена классов, но вместо этого объекты класса напрямую. Во время выполнения вполне может существовать несколько разных классов с одинаковым именем (имя уникально только в наборе классов, загружаемых одним загрузчиком классов, но может быть и несколько загрузчиков классов).