Java: общие типы в токенах типа

У меня есть класс, который принимает маркер типа, а затем генерирует объекты типа, параметризованные этим типом (ОК, это немного сложнее, чем это, но это краткий пример):

public class Test {
 public static void main(String[] args) throws Exception {
 Holder<hashset<integer>> i = newObjectHolder(HashSet.class); // this fails
 }
 static class Holder<t> {
 public Holder(T newInstance) {}
 }
 public static <t> Holder<t> newObjectHolder(Class<t> typeToken) throws Exception {
 Constructor<t> ctor = typeToken.getConstructor();
 return new Holder<t>(ctor.newInstance());
 }
}
</t></t></t></t></t></t></hashset<integer>

Это работает отлично, если передаются не общие типы, например:

Holder<integer> i = Test.newObjectHolder(Integer.class);
</integer>

Если маркер прошедшего типа является общим, он не работает, как в указанной строке выше:

Holder<hashset<integer>> i = Test.newObjectHolder(HashSet.class); // this fails
</hashset<integer>

У меня проблема, но есть ли решение? Я в порядке, чтобы добавить @SuppressWarnings ( "unused" ) в код для newObject, если это не снижает безопасность. Интуитивно кажется, что newObject должен иметь возможность сделать бросок, который работает, мы знаем, что один "новый" объект стираемого родового типа такой же, как и любой другой, и мы в противном случае не использовали T в методе.

2 ответа

Итак, застенчиво, отвечая на мой собственный вопрос...

Я не могу найти способ сделать это с помощью Class <!--?-->, но этот волшебный метод, называемый токенами типа super, кажется, работает хорошо. Здесь обновленный код:

public class Test {
 static class A {}
 static class B extends A {}
 public static void main(String[] args) throws Exception {
 Holder<hashset<integer>> i = newObjectHolder(new TypeReference<hashset<integer>>() {}); // works
 Holder<a> j = newObjectHolder(new TypeReference</a><a>() {}); // works
 Holder</a><a> k = newObjectHolder(new TypeReference<b>() {}); // works
 Holder<b> l = newObjectHolder(new TypeReference</b></b></a><b><b><a>() {}); // doesn't compile (good)
 }
 static class Holder<t> {
 public Holder(T newInstance) {}
 T get() { return null; }
 }
 public static <t,u extends="" typereference<?="" t="">> Holder<t> newObjectHolder(U typeToken) throws Exception {
 T obj = typeToken.newInstance();
 return new Holder<t>(obj);
 }
}
</t></t></t,u></t></a></b></b></hashset<integer></hashset<integer>

Код TypeReference указан здесь, хотя я подозреваю, что Guice TypeLiteral будет работать так же хорошо (но у него нет кода newInstance, вам придется его реализовать).


В вашем обновленном коде вы все равно можете

Holder<hashset> i = newObjectHolder(HashSet.class);
</hashset>

но не может

Holder<hashset<integer>> i = newObjectHolder(HashSet.class);
</hashset<integer>

Старый ответ:

Я не уверен, в чем проблема, которую вы получаете. Этот код работает хорошо.

public class Test {
 public static void main(String[] args) throws Exception {
 @SuppressWarnings("unchecked")
 HashSet<integer> i = newObject(HashSet.class);
 i.add(new Integer(42));
 i.add(new Integer(666));
 System.out.println(i.size() +":" + Arrays.toString(i.toArray()));
 }
 public static <t> T newObject(Class<t> typeToken) throws Exception {
 Constructor<t> ctor = typeToken.getConstructor();
 return ctor.newInstance();
 }
}
</t></t></t></integer>

печатает

2:[666, 42]

Я что-то пропустил? Забастовкa >

licensed under cc by-sa 3.0 with attribution.