简体   繁体   中英

Java - weird generics behavior with arrays

I was trying to implement some kind of custom serialization with reflection, and then I found out that you just cannot cast A[] to B[] if A isn't a subtype of B even if all the elements in the array are subtypes of B (It should work because of type erasing because at the end of the day both a[] and b[] are Object[] ).

here is an example of what I mean:

public class Foo {
    public static void main(String[] args) throws Exception {
        new Foo().testGenerics();
    }


    public LinkedList<String> strList;
    public String[] strArr;

    public void testGenerics() throws Exception {

        LinkedList<Object> objList = new LinkedList<Object>();
        objList.add("foo");


        Object[] objArr = new Object[1];
        objArr[0] = "bar";

        Foo.class.getField("strList").set(this, objList);

        System.out.println("list[0]  = " + strList.get(0));
        System.out.println("list len = " + strList.size());

        Foo.class.getField("strArr").set(this, objArr);

        System.out.println("arr[0]  = " + strArr[0]);
        System.out.println("arr len = " + strArr.length);

    }

}

In this example the list works fine but the array throws an exception at the line that tries to set it.

is there any reason arrays ignore type erasing, and is there any good way to create an array and a list for a given type at runtime?

Arrays and generics are very different things. Generics are erased at runtime because the JVM doesn't know about them. However, the JVM does know about arrays. If you search in the JVM specification for "array", you'll see that section 3.9 is titled "Arrays". But you can't find anything about generics, or parameterised types. You can read section 3.9 in more detail to find out just how much the JVM knows about arrays. The Java Language Specification also talks about arrays and generics in very different sections.

Therefore, the JVM at runtime, can and does try to maintain the type safety of arrays, and stops you from assigning Object[] to String[] . This is analogous to the Java Compiler trying to maintain the type safety of LinkedList s at compile time by stopping you from assigning a LinkedList<Object> to a LinkedList<String> . It's not like the latter is somehow "safe to do" at runtime, it's just that the runtime doesn't know enough to stop you.

is there any good way to create an array and a list for a given type at runtime?

Given the Class<?> clazz and the length , you can create an array of it by:

Object o = Array.newInstance(clazz, length);

But having to do this smells like an XY problem ... Make sure you know what you are doing.

You can create a list using the way you are using right now. It's not type safe, but that's a flaw of JVM/Java.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM