Search code examples
javaarraysreflectioncasting

How to directly cast array of Objects to array of Integer without modifications


I have an Objects array filled up with Strings:

Object[] array = new Object[count];
for (int i = 0; i < array.length; i++) {
  array[i] = String.valueOf(i);
}

Then I refill it with Integers:

for (int i = 0; i < array.length; i++) {
  array[i] = Integer.parseInt(array[i]);
}

I want to return an object of type Integer[]. When I do:

return (Integer[]) array;

or

return Integer[].class.cast(array);

I get Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.Integer; ([Ljava.lang.Object; and [Ljava.lang.Integer; are in module java.base of loader 'bootstrap').

I don't want to use streams, copying array or any other modifications or transformations. Just direct casting, maybe even via reflection.

Are there any options?


Solution

  • It's not an array, but you can do this with a generic list and unchecked casting using a wildcard list: List<?>. You can even cast it when it contains objects of different types, it'll throw a ClassCastException when you try to access them as the generic type.

    ArrayList<Object> arr = new ArrayList<Object>();
    arr.add(1);
    arr.add("xyz");
    
    @SuppressWarnings("unchecked")
    ArrayList<Integer> casted = (ArrayList<Integer>) (ArrayList<?>) arr;
    
    System.out.println(casted.get(0)); // Prints 1
    System.out.println(casted.get(1)); // Prints "xyz"
            
    Integer first = casted.get(0); // Works!
    // Integer second = casted.get(1); // Throws ClassCastException at runtime
    // String secondStr = casted.get(1); // Doesn't compile, 'incompatible types'
    String secondStrGood = (String) (Object) casted.get(1); // Works!
    

    This is because ArrayLists just use an Object[] array instead of a generic T[] array, and casts on get (sort of...)


    If you try to be sneaky and retrieve the internal array backing an ArrayList through reflection, no dice there. It's just a normal Object[] array as previously mentioned, so you get the same casting issue.

    Field privateField = casted.getClass().getDeclaredField("elementData"); 
    privateField.setAccessible(true); 
    
    // java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
    Integer[] array = (Integer[]) privateField.get(casted); 
    

    If you try to be even sneakier and try this trick with a generic class instead of a List<?>, it still doesn't work.

    public class Test<T> {
        public T[] array;
    }
        
    public static void main(String args[]) {
        Object[] objArray = new Object[] {1, "string"};
    
        Test<Object> test = new Test<Object>();
        test.array = objArray;
            
        @SuppressWarnings("unchecked")
        Test<Integer> testInteger = (Test<Integer>) (Test<?>) test;
    
        // java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
        Integer[] intArray = testInteger.array;
    }
    

    TL;DR: best you can do is with Collections