Вот как использовать универсальные шаблоны, чтобы получить массив именно того типа, который вы ищете, сохраняя при этом безопасность типа (в отличие от других ответов, которые либо вернут вам массив Object
, либо приведут к предупреждению во время компиляции):
import java.lang.reflect.Array;
public class GenSet<E> {
private E[] a;
public GenSet(Class<E[]> clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet<String> foo = new GenSet<String>(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
}
}
Это компилируется без предупреждений, и, как вы можете видеть в main
, для любого типа, который вы объявляете экземпляр GenSet
as, вы можете назначить a
массиву этого типа, и вы можете назначить элемент из a
переменной этого типа, Это означает, что массив и значения в массиве имеют правильный тип.
Он работает с использованием литералов классов в качестве маркеров типа среды выполнения, как описано в Руководствах по Java.. Литералы классов рассматриваются компилятором как экземпляры java.lang.Class
. Чтобы использовать один, просто введите имя класса с помощью .class
. Итак, String.class
действует как Class
объект, представляющий класс String
. Это также работает для интерфейсов, перечислений, любых размерных массивов (например, String[].class
), примитивов (например, int.class
) и ключевого слова void
(например, void.class
).
Class
сам по себе является универсальным (объявлен как Class<T>
, где T
обозначает тип, который представляет объект Class
), что означает, что тип String.class
- Class<String>
.
Итак, всякий раз, когда вы вызываете конструктор для GenSet
, вы передаете литерал класса для первого аргумента, представляющего массив объявленного типа экземпляра GenSet
(например, String[].class
для GenSet<String>
). Обратите внимание, что вы не сможете получить массив примитивов, поскольку примитивы не могут использоваться для переменных типа.
Внутри конструктора вызов метода cast
возвращает переданный аргумент Object
, приведенный к классу, представленному объектом Class
, для которого был вызван метод. Вызов статического метода newInstance
в java.lang.reflect.Array
возвращает как Object
массив типа, представленного объектом Class
, переданным в качестве первого аргумента, и длины, указанной в int
, переданном в качестве второго аргумента. Вызов метода getComponentType
возвращает объект Class
, представляющий тип компонента массива, представленного объектом Class
, для которого был вызван метод (например, String.class
для String[].class
, null
, если объект Class
не представляет массив).
Последнее предложение не совсем точное. Вызов String[].class.getComponentType()
возвращает объект Class
, представляющий класс String
, но его тип - Class<?>
, а не Class<String>
, поэтому вы не можете сделать что-то вроде следующего.
String foo = String[].class.getComponentType().cast("bar"); // won't compile
То же самое касается каждого метода в Class
, который возвращает объект Class
.
Что касается комментария Иоахима Зауэра к этому ответу (я не иметь достаточно репутации, чтобы прокомментировать это сам), пример с приведением к T[]
приведет к предупреждению, потому что в этом случае компилятор не может гарантировать безопасность типов.
Отредактируйте комментарии Инго:
public static <T> T[] newArray(Class<T[]> type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));
}
person
gdejohn
schedule
19.11.2010