简体   繁体   English

Java - 奇怪的 generics 行为与 arrays

[英]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[] ).我试图用反射实现某种自定义序列化,然后我发现如果 A 不是 B 的子类型,即使数组中的所有元素都是子类型,你也不能将A[]转换为B[] B(它应该因为类型擦除而起作用,因为在一天结束时a[]b[]都是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 是否有任何理由忽略类型擦除,是否有任何好方法可以在运行时为给定类型创建数组和列表?

Arrays and generics are very different things. Arrays 和 generics 是非常不同的东西。 Generics are erased at runtime because the JVM doesn't know about them. Generics 在运行时被擦除,因为 JVM 不知道它们。 However, the JVM does know about arrays.但是,JVM确实知道 arrays。 If you search in the JVM specification for "array", you'll see that section 3.9 is titled "Arrays".如果您在JVM 规范中搜索“array”,您会看到第 3.9 节的标题为“Arrays”。 But you can't find anything about generics, or parameterised types.但是您找不到任何关于 generics 或参数化类型的信息。 You can read section 3.9 in more detail to find out just how much the JVM knows about arrays.您可以更详细地阅读第 3.9 节,以了解 JVM 对 arrays 了解多少。 The Java Language Specification also talks about arrays and generics in very different sections. Java 语言规范还在非常不同的部分讨论了arraysgenerics

Therefore, the JVM at runtime, can and does try to maintain the type safety of arrays, and stops you from assigning Object[] to String[] .因此,JVM 在运行时可以并且确实尝试维护 arrays 的类型安全,并阻止您将Object[]分配给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> .这类似于 Java 编译器试图通过阻止您将LinkedList<Object>分配给LinkedList<String> > 来在编译时维护LinkedList的类型安全。 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:给定Class<?> clazzlength ,您可以通过以下方式创建它的数组:

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

But having to do this smells like an XY problem ... Make sure you know what you are doing.但是必须这样做闻起来像一个XY 问题......确保你知道你在做什么。

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.它不是类型安全的,但这是 JVM/Java 的一个缺陷。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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