36

Here is a variable Class<?> cls, now I want to get another Array Class Object which component type is cls.

For example, if cls=String.class , I want to get String[].class; if cls=int.class, I want to get int[].class, what should I do?

You see, It's quite easy to get String.class from String[].class:

Class<?> arrayCls = String[].class;
if(arrayCls.isArray()){
    Class<?> cls = arrayCls.getComponentType();
}

But I cannot find easy way to do the reverse.

Here is one possible solution:

Class<?> clazz = String.class;
Class<?> arrayClass = Array.newInstance(clazz,0).getClass();

Is there any batter way to do this please?

4
  • 1
    What's wrong with that solution? Commented Nov 15, 2012 at 5:47
  • @Thilo The solution is a result of my guess. It works fine, but I'm not sure if this is the best way. This solution need to dynamic create an array entity which length is 0. Commented Nov 15, 2012 at 5:52
  • Interesting question. Just curious why you need the array Class object? Commented Nov 15, 2012 at 6:32
  • Array.newInstance(clazz,0) creates a short-lived object on the operand stack, the JIT might optimize that away but I wouldn't count on it. Commented Nov 5, 2019 at 1:37

3 Answers 3

18

HRgiger's answer improved:

@SuppressWarnings("unchecked")
static <T> Class<? extends T[]> getArrayClass(Class<T> clazz) {
    return (Class<? extends T[]>) Array.newInstance(clazz, 0).getClass();
}

Both of them instantiate an array object when invoked. To get the array type, use

Class<?> childType = ...;
Class<?> arrayType = getArrayClass(childType);
Sign up to request clarification or add additional context in comments.

4 Comments

This has nothing to do with HRgiger’s answer, this is an improvement of what the OP posted in the question.
Also, I'm pretty sure you're instantiating a new object here, every time, which the other answer isn't.
Beware that this unchecked cast is broken if you pass it a primitive type. For example, int.class is a Class<Integer>, but int[].class is a Class<int[]>, not a Class<Integer[]>. The method should just return a Class<?>, or it should check if clazz.isPrimitive() and throw an exception if it is.
Why <? extends T[]>? I understand why getClass() returns that in general, but in this case, we know that the array has the exact type T[] (assuming clazz isn't primitive, but that breaks this anyway), so as long as we're doing an unchecked cast anyway, why not be more precise?
10

Maybe try Class.forName(String)?

Edit: Here is a code snippet.

Class<?> arrayClass = String[].class;
System.out.println(arrayClass);
Class<?> namedClass = Class.forName("[L" + String.class.getName() + ";");
System.out.println(namedClass);
System.out.println(arrayClass == namedClass);

5 Comments

According XMLEncoder Class in jdk, Class.forName(String) is the standard method to do this. Thanks dude. Class<?> cls=String.class; Class<?> arrayCls=Class.forName("[L"+cls.getName()+";"); stackoverflow.com/questions/4581394/…
Ah. I forgot about the semicolon at the end.
Personally I prefer your solution using Array.newInstance. This at least uses documented features. But the name prefix [L is an internal convention. In the future they could change it and change the XMLEncoder class, because that's part of the JDK also. Just because something does something in a certain way in the JDK, doesn't mean that's the way you should do it, because you are writing application code rather than JDK code.
@Kidburla: The naming is more than a convention. Still, creating a single zero sized array is way cheaper than the string concatenation, not to speak of the dynamic class lookup performed in Class.forName afterwards. And if you have an arbitrary Class object, Class.forName("[L"+clazz.getName()+";"); will fail if clazz represents a primitive type or an array type, so the bottom line is, Array.newInstance(clazz,0).getClass() is way better
@Holger Should write an answer. You are 100000% correct. OP even mentioned the requirement of primitives & dynamic nature requirement (latter is mentioned in comments). It's as if the OP isn't testing their code against the requirements they specified. I know this question is old, but you'd probably pass the current accepted answer within time, and it's more introspective of the situation at hand.
10

Another trick I found is using varargs on util method.

public static void main(String[] args) throws ClassNotFoundException {

    Class<?> demo = Main.<String>getArrayClass();
    System.out.println(demo);
}

static <T> Class getArrayClass(T... param){
    return param.getClass();
}

6 Comments

Nice trick +1 Actually if you specify T at the call site there's no need to pass any arguments: MyClass.<String>getArrayClass();
Why won't this return the class of Object[] everytime because of runtime type erasure?
Very nice trick. It does not help the OP though, because you need to know the class in compile time. And if you know at compile time that it's String, you can just say String[].class.
@SpaceTrucker, Saintali right, I didnt spent much time, because there is already a solution, just wanted to share maybe for similar cases can be good option:)
@SpaceTrucker, this is a late response but after looking into this it appears that type erasure doesn't apply here because the varargs argument type is known at compile time for the method call. If we didn't know the argument type (e.g., <U> void otherMethod(U obj) { System.out.println(getArrayClass(obj)); }) then type erasure would apply and T... param would be always be an Object[], in which case Object[].class would always be returned.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.