Obtaining the array Class of a component type
If I have an instance of Class
, is there a way of obtaining a Class
instance for its array type? What I'm essentially asking for is the equivalent of a method getArrayType
which is the inverse of the getComponentType()
method, such that:
array.getClass().getComponentType().getArrayType() == array.getClass()
One thing that comes to mind is:
java.lang.reflect.Array.newInstance(componentType, 0).getClass();
But it creates an unnecessary instance.
Btw, this appears to work:
Class clazz = Class.forName("[L" + componentType.getName() + ";");
Here is test. It prints true
:
Integer[] ar = new Integer[1];
Class componentType = ar.getClass().getComponentType();
Class clazz = Class.forName("[L" + componentType.getName() + ";");
System.out.println(clazz == ar.getClass());
The documentation of Class#getName()
defines strictly the format of array class names:
If this class object represents a class of arrays, then the internal form of the name consists of the name of the element type preceded by one or more '[' characters representing the depth of the array nesting.
The Class.forName(..)
approach won't directly work for primitives though - for them you'd have to create a mapping between the name (int
) and the array shorthand - (I
)
Actually due to ClassLoader
, primitives and multi-dimensional arrays, the answer is a little more complex:
public static Class<?> getArrayClass(Class<?> componentType) throws ClassNotFoundException{
ClassLoader classLoader = componentType.getClassLoader();
String name;
if(componentType.isArray()){
// just add a leading "["
name = "["+componentType.getName();
}else if(componentType == boolean.class){
name = "[Z";
}else if(componentType == byte.class){
name = "[B";
}else if(componentType == char.class){
name = "[C";
}else if(componentType == double.class){
name = "[D";
}else if(componentType == float.class){
name = "[F";
}else if(componentType == int.class){
name = "[I";
}else if(componentType == long.class){
name = "[J";
}else if(componentType == short.class){
name = "[S";
}else{
// must be an object non-array class
name = "[L"+componentType.getName()+";";
}
return classLoader != null ? classLoader.loadClass(name) : Class.forName(name);
}
You can do the following
array.getClass() ==
Array.newInstance(array.getClass().getComponentType(), 0).getClass()
Usually, you don't need to know the type, you just want to create the array.
Another possible refactoring is to use a generic superclass and pass in two class objects to the constructor.
protected AbstractMetaProperty(Class<T> valueClass, Class<T[]> valueArrayClass) {
this.valueClass = valueClass;
this.valueArrayClass = valueArrayClass;
}
Then in subclasses:
public IntegerClass() {
super(Integer.class, Integer[].class);
}
Then in the abstract class you can use valueClass.cast(x)
, valueArrayClass.isInstance(x)
etc.
Java 12 introduced arrayType()
String.class.arrayType() == String[].class;