[英]Generic type casting vs parameterized type casting in Java
I know the general differences between generic types and parameterized types, and I know some general rules:我知道泛型类型和参数化类型之间的一般区别,并且我知道一些一般规则:
List<A> and List<B> have no inheritance relationship, even if A and B are related through an inheritance chain; List<A> 和 List<B> 没有 inheritance 关系,即使 A 和 B 通过 inheritance 链相关;
Object[] cannot be cast to String[], unless the Object[] array was constructed using new String[n]. Object[] 不能转换为 String[],除非 Object[] 数组是使用 new String[n] 构造的。
But my question is a bit specific.但我的问题有点具体。 So I am going to give some code.所以我要给出一些代码。
According to the above general rules, the cast in the following 2 examples is invalid:根据上述一般规则,以下 2 个示例中的强制转换无效:
static List<String> f1a(List<String> list) {
return List.of((String[]) list.toArray()); // ClassCastException
}
static List<String> f2a(List<String> list) {
return (List<String>) List.of(list.toArray()); // compile-time error: Inconvertible types
}
Now if I replace the String type with a generic type parameter E, the casting works?现在,如果我用泛型类型参数 E 替换 String 类型,转换是否有效? But I really don't understand why?但我真的不明白为什么?
// f1 is a generic version f1a, where String -> E
static <E> List<E> f1(List<E> list) {
return List.of((E[]) list.toArray());
}
// f2 is a generic version f2a, where String -> E
static <E> List<E> f2(List<E> list) {
return (List<E>) List.of(list.toArray());
}
The following demo shows that f1 and f2 are valid, while f1a and f2a are problematic:下面的demo显示f1和f2是有效的,而f1a和f2a是有问题的:
public static void main(String[] args) {
List<String> list = List.of("hello", "world");
List<String> copy1 = f1(list); // works
System.out.println(copy1);
List<String> copy2 = f2(list); // works
System.out.println(copy2);
List<String> copy1a = f1a(list); // ClassCastException
System.out.println(copy1a);
List<String> copy2a = f2a(list); // compile-time error
System.out.println(copy2a);
}
f1
works because of type erasure. f1
由于类型擦除而起作用。 The cast to E[]
is completely removed at runtime, meaning that your code would behave something like this at runtime, but it does let the compiler infer that you're returning a List<E>
and not a List<Object>
, therefore letting the program compile.对E[]
的强制转换在运行时被完全删除,这意味着你的代码在运行时会表现得像这样,但它确实让编译器推断你返回的是List<E>
而不是List<Object>
,因此让程序编译。
static List f1(List list) {
return List.of(list.toArray());
}
f2
works because of basically the same reason. f2
的工作原理基本相同。 This time, the result of List.of(list.toArray())
is inferred to be a List<Object>
because toArray
returns an Object[]
, but the cast, which is later erased, makes it compile.这一次, List.of(list.toArray())
的结果被推断为一个List<Object>
因为toArray
返回一个Object[]
,但是后来被擦除的强制转换使其编译。
f1a
has a ClassCastException
because you're trying to turn an Object[]
into a String[]
. f1a
有一个ClassCastException
因为您试图将Object[]
转换为String[]
。 In Java, arrays know the type they were declared with even at runtime, so the array returned by toArray
thinks of itself as an Object[]
even though it really only holds strings and doesn't like being turned into a String[]
.在 Java 中,arrays 即使在运行时也知道它们声明的类型,因此toArray
返回的数组将自己视为Object[]
即使它实际上只包含字符串并且不喜欢变成String[]
。
f2a
doesn't work because you can't turn a List<Object>
into a List<String>
. f2a
不起作用,因为您无法将List<Object>
变成List<String>
。
If you want to turn your list into an array of strings, try list.toArray(new String[0])
.如果要将列表转换为字符串数组,请尝试list.toArray(new String[0])
。 This way, it will return a proper String[]
and not cause problems.这样,它将返回正确的String[]
而不会引起问题。
If you convert a List<Object>
to a List<String>
, cast to a raw type with (List) List.of(list.toArray())
如果将List<Object>
转换为List<String>
,请使用(List) List.of(list.toArray())
转换为原始类型
f1a
case: f1a
案例:
Here, the explicit casting is done, which means that compiler expects the same type at the compile time.在这里,显式转换完成,这意味着编译器在编译时期望相同的类型。 By providing explicit cast (String[]) list.toArray()
, you tell to your compiler, that whatever is returned by .toArray()
, it should attempt to cast it to String[]
, and hence you want to build a List.of(String[])
, which also constitutes a return type of your method.通过提供显式(String[]) list.toArray()
,您告诉编译器,无论.toArray()
返回什么,它都应该尝试将其转换为String[]
,因此您想要构建一个List.of(String[])
,它也构成了您的方法的返回类型。 This is why it doesn't have any compile-time problem, but rather it throws run-time exception, as it can't cast Object
to String
.这就是为什么它没有任何编译时问题,而是抛出运行时异常,因为它不能将Object
为String
。 Think of it as at the compile time, explicitly given instruction is correct for the compiler, but it doesn't work at run-time.把它想象成在编译时,明确给出的指令对编译器是正确的,但它在运行时不起作用。 To understand more about casting, please also see Checked Casts at Runtime and maybe also type erasure .要了解有关强制转换的更多信息,请参阅运行时检查强制转换,也可以键入擦除。
f2a
case: f2a
案例:
.toArray()
method of ArrayList
, by method definition returns Object[]
. ArrayList
的.toArray()
方法, 通过方法定义返回Object[]
。 That's why you get the list of objects, which can't be downcasted to list of Strings, and this happens, because it can't cast it and this is a checked cast , and you get compile-time Exception, ie your code doesn't compile.这就是为什么你得到对象列表,它不能被向下转换为字符串列表,这会发生,因为它不能转换它,这是一个检查转换,你得到编译时异常,即你的代码没有不编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.