2013-07-31 2 views
1

Ниже приведен пример кода, который требует получения имени класса массива, который неизвестен во время выполнения:Каков безопасный способ получить имя класса массива во время выполнения?

//for calling methods declared similar to 
// void method(String... values); 
//For primitive type we have other overloads and the following 
//is generic for classes 

@SuppressWarnings("unchecked") 
private static <T> void invokeVaridic(Method m, Object host, T... values) 
    throws IllegalAccessException, IllegalArgumentException, 
    InvocationTargetException, ClassNotFoundException{ 

    assert(values.length>0); //We assume all users passes at least one value 
    Class<? extends T[]> c = (Class<? extends T[]>) 
      Class.forName("[L" + values[0].getClass().getName() + ";"); 
    m.invoke(host, Arrays.copyOf(values, values.length,c)); 
} 

Поскольку тип стирания природы тип values на самом деле Object[], я не могу передать это m.invoke потому, что он требуется String[]. Однако, поскольку я заставляю пользователя передавать хотя бы одно значение, я могу использовать тип values[0] для построения нового массива.

Я не знаю, что такое T[].class.

Я придумал код, который зависит от интерпретации имени массива в байтовом коде, но безопасен ли он? Каков предложенный способ получить T[].class?

+0

GetClass() на любой объект будет возвращать его во время выполнения класса, и GetClass() GetName() возвращает класс. имя как строка. Выполнение getClass(). GetName(), за которым следует classForName(), - это просто неэффективный способ сделать getClass(). –

+0

И выполнение 'Class.forName (" [L "+ values ​​[0] .getClass(). GetName() +"; ")' является неэффективным способом делать values.getClass(). –

ответ

0

Вы не всегда можете быть уверены, что значения в values будут фактически иметь тип T, так как массивы с тире стираются под воздействием кучного загрязнения, и вы должны быть готовы иметь дело с ClassCastException в том месте, которое вы выполняете. Тем не менее, вы можете получить тип массива для конкретного объекта с помощью слегка извилистый вызова Array.newInstance:

Class<?> arrayClass = Array.newInstance(values[0].getClass(), 1).getClass(); 
+0

Как это отличается от выполнения значений [0] .getClass() ??? –

+0

@HotLicks 'values ​​[0] .getClass()' получает класс элемента в позиции 0, а не сам класс массива. – chrylis

+0

Хорошо, ты меня достал. Непонятно, что ОП пытается сузить класс массива. Но, конечно, он должен проверять все элементы массива. Первым элементом может быть строка, второй элемент может быть картофелем. –

4

values имеет тип T[]:

Class<? extends T[]> arrayType = (Class<? extends T[]>) values.getClass(); 
Class<? extends T> component = (Class<? extends T>) values.getClass().getComponent(); 

/редактировать

полный пример:

public class GenericArray { 
    public static void main(String[] args) { 
     foo("", ""); 
    } 

    @SafeVarargs 
    public static <T> void foo(T... args) { 
     Class<? extends T[]> array = (Class<? extends T[]>) args.getClass(); 
     Class<? extends T> component = (Class<? extends T>) array.getComponentType(); 
     System.out.println(array); 
     System.out.println(component); 
    } 
} 

печатает следующую с JDK 1.7.0_25

class [Ljava.lang.String; 
class java.lang.String 
+0

Во время выполнения 'values' будет иметь тип' Object [] ', даже если' T' был 'String' во время компиляции. – chrylis

+0

@chrylis Нет, этого не будет. Попробуйте, это работает. – Jeffrey

+0

Я оговорился; большую часть времени, с правильным кодом, 'values' на самом деле будет иметь правильный тип. Тем не менее, можно пройти в массив bare 'Object'; там [конкретное предупреждение компилятора] (http://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html) об этом случае. – chrylis

Смежные вопросы