在编译时,新的T5会发生错误,称为=>错误:泛型数组的创建,据我的理解,数组是在编译时创建的,而且由于我们在编译时不知道T的类型,所以不能实例化数组。但是,如果T在编译时被擦除并更改对象,那么为什么还会发生此错误呢?因为我们可以创建一个对象数组。
// Before Compiling
public class GenericClass<T> {
GenericClass(){
T[] obj = new T[5];
}
}
// After Compiling
public class GenericClass {
GenericClass() {
Object[] obj = new Object[5];
}
}类似的情况,就像,
public class GenericClass<T> {
GenericClass(){
T obj = new T(); }}
/* error :required: class
found: type parameter T
where T is a type-variable:
T extends Object declared in class GenericClass*/发布于 2022-04-17 08:17:53
根据我的理解,数组是在编译时创建的。
不,数组是在运行时创建的。
由于我们在编译时不知道T的类型,所以不能实例化数组。
对,是这样。
,但是如果T在编译时被擦除并更改对象,那么为什么还会发生此错误呢?
因为“它在编译时被擦除并更改对象”被过度简化。
而且,泛型和数组之间并不友好。问题是,在删除泛型部分的地方,数组不像那个那样工作。你可以这样做:
String[] x = new String[10];
tellMeTheTypeOfMyArray(x);
void tellMeTheTypeOfMyArray(Object[] o) {
System.out.println("Your array's component type is: " + o.getClass().getComponentType());
}此代码将编译和工作良好,没有错误,并打印:
Your array's component type is: java.lang.String与泛型不同,在泛型中,不能编写这种方法。你不可能这样做:
List<String> x = new ArrayList<String>();
tellMeTheTypeOfMyList(x);
void tellMeTheTypeOfMyList(List<?> o) {
System.out.println("Your list's component type is: " + ??????);
}工作。这里不可能有java代码,您不能用任何东西来代替?打印字符串,因为该信息在运行时根本不存在。
想象一下这段代码:
// This is written by Wahab today.
class Example<T> {
protected T[] arr;
Example() {
this.arr = new T[10];
}
}照你想的那样做了。那我就做:
// Written by me, a year later
class Uhoh extends Example<String> {
Uhoh() {
super();
}
void hmmm() {
System.out.println(this.arr.getComponentType());
}
}我显然期望,不,要求--这个打印java.lang.String,但是它不可能这样做,。因为这是奇怪和令人困惑的,java有一条规则:如果您编译代码而没有看到任何关于泛型问题的警告(并且没有@SuppressWarnings ),那么这种混淆是不可能发生的。
允许您编写new T[],而这只是编写new Object[]的一种愚蠢的方式,这被认为是远远不够的。
那么,如何在泛型类型中使用数组呢?
与java.util.ArrayList一样:在这里不使用泛型()。如果您打算在泛型代码中创建数组,那么数组几乎不应该有T类型。如果您的代码库中任何地方都有一个T[],那么这意味着您永远不应该为它做任何事情--让代码的调用者为您做这件事。如果您确实希望自己创建新的数组,不要使用T,使用new作为类型,并在需要时转换为T。这就是java内置的ArrayList类的工作原理。一些摘录是从原著中直接粘贴过来的:
transient Object[] elementData; // non-private to simplify nested class access
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}这里有一个例子,同样直接来自ArrayList的源代码(或者更确切地说,java.util.Collection定义了它,ArrayList继承了它),在这里,您可以让调用者为您提供代码来生成数组:
default <T> T[] toArray(IntFunction<T[]> generator) {
return toArray(generator.apply(0));
}在这里,调用方提供了一个将int转换为T[]的函数--它接受了执行new String[10]的概念,并将其转化为函数,然后将其传递给toArray方法,后者将使用它(尽管您可以忽略它在这里的使用方式,这是一个有点奇怪的解决方案。它起作用了,只是--不确定你是否应该从中吸取教训)。
你就这样用它:
List<String> listOfStrings = ...;
String[] convertedToArray = listOfStrings.toArray(String[]::new);发布于 2022-05-01 06:48:00
Java数组在运行时知道它们的组件类型。创建数组时,必须在运行时提供组件类型。但是在您的GenericClass中,它不能这样做,因为它不知道T在运行时是什么。如果它创建了一个Object[],那么该对象将有错误的运行时类,并且如果T[]不是Object,那么该实例与T类型不兼容。你是对的,在课堂上,没有什么是立即错的。但是,如果变量是T[]的声明暴露在外部作用域中,期望T是更特定的类型,则会导致ClassCastException。
// Before type erasure
class GenericClass<T> {
T[] obj;
GenericClass() {
obj = new T[5]; // if hypothetically you could do this
}
T[] getObj() {
return obj;
}
}
class MyCode {
public static void main(String[] args) {
GenericClass<String> foo = new GenericClass<>();
String[] strings = foo.getObj(); // no casts needed; no warnings
}
}
// After type erasure
class GenericClass {
Object[] obj;
GenericClass() {
obj = new Object[5];
}
Object[] getObj() {
return obj;
}
}
class MyCode {
public static void main(String[] args) {
GenericClass foo = new GenericClass();
String[] strings = (String[]) foo.getObj(); // ClassCastException at runtime
}
}https://stackoverflow.com/questions/71900220
复制相似问题