Java I';当使用varargs传递给第二个泛型方法时,我将丢失泛型方法中的变量类型
我想最好从我所看到的行为开始:Java I';当使用varargs传递给第二个泛型方法时,我将丢失泛型方法中的变量类型,java,generics,Java,Generics,我想最好从我所看到的行为开始: public class genericTest { public static void main(String[] args) { String str = "5318008"; printClass(str); // class java.lang.String callPrintClass(str); // class java.lang.String
public class genericTest {
public static void main(String[] args) {
String str = "5318008";
printClass(str); // class java.lang.String
callPrintClass(str); // class java.lang.String
printClassVarargs(str); // class java.lang.String
callPrintClassVarargs(str); // class java.lang.Object
}
public static <T> void printClass(T str) {
System.out.println(str.getClass());
}
public static <T> void printClassVarargs(T ... str) {
System.out.println(str.getClass().getComponentType());
}
public static <T> void callPrintClass(T str) {
printClass(str);
}
@SuppressWarnings("unchecked")
public static <T> void callPrintClassVarargs(T str) {
printClassVarargs(str);
}
}
公共类泛型测试{
公共静态void main(字符串[]args){
字符串str=“5318008”;
printClass(str);//class java.lang.String
callPrintClass(str);//class java.lang.String
printClassVarargs(str);//class java.lang.String
callPrintClassVarargs(str);//类java.lang.Object
}
公共静态无效打印类(T str){
System.out.println(str.getClass());
}
公共静态无效printClassVarargs(T…str){
System.out.println(str.getClass().getComponentType());
}
公共静态void callPrintClass(T str){
打印类(str);
}
@抑制警告(“未选中”)
公共静态void callPrintClassVarargs(T str){
printclassvargs(str);
}
}
看看printClass()
和callPrintClass()
,似乎一切都很正常callPrintClass()
接受一个泛型参数并传递它printClass()
通过正确的类型识别此变量,而不管是谁发送参数,然后按照它的预期操作并打印java.lang.String
但是当我们尝试使用varargs时,它就停止工作了。我希望printClassVarargs()
能够识别它的参数类型为String[]
,这与不带varargs的方法识别其参数类型非常相似。还要注意,如果我直接调用printClassVarargs()
(在那里输出String
,这是非常愉快的),但只有当它被callPrintClassVarargs()
调用时才会发生这种情况,因为它忘记了参数的类型,并假定它得到了一个对象。我还意识到我必须在这里抑制编译器警告,这通常是在我尝试转换泛型时出现的,但我不确定那里到底发生了什么
所以我的问题是两个。这种行为背后的原因是什么?这是类型擦除的结果,还是Java处理数组的方式?第二,有没有办法解决这个问题
当然,这只是一个简单的例子。我不想用这种方式打印类名,但最初是在编写重载方法连接数组时发现问题的 我认为问题归结为无法创建泛型类型的数组。如果callPrintClassVarargs
被修改为显式创建一个新的数组实例并将其传递给printClassVarargs
,则潜在问题将变得明确
// doesn't work, gives compiler error (cannot create array of generic type)
public static <T> void callPrintClassVarargs(T str) {
printClassVarargs(new T[]{str});
}
//This works
public static <T> void callPrintClassVarargs(T str) {
printClassVarargs(new Object[]{str});
}
//不工作,出现编译器错误(无法创建泛型类型的数组)
公共静态void callPrintClassVarargs(T str){
printclassvargs(新的T[]{str});
}
//这很有效
公共静态void callPrintClassVarargs(T str){
printClassVarargs(新对象[]{str});
}
-
这个问题涉及为什么不可能创建泛型类型的数组,也许同样可以解释这个问题 Varargs是由编译器转换为给定类型数组的语法糖。
这意味着方法(类型arg…
将成为方法(类型[]arg)
在Java中,不能创建(类型信息因擦除而丢失的类型)的数组。因此,诸如printclassrargs(T…str)
之类的泛型varargs将转换为printclassrargs(Object[]str)
,从而有效地删除类型信息。这就是你在测试中观察到的情况
---编辑---
要回答您关于printClassVarargs(str)
和callPrintClassVarargs(str)
之间差异的问题(cfr注释),我们可以查看您测试类的字节码,以获得所需的线索:
public Test();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #16; //String 5318008
2: astore_1
3: aload_1
4: invokestatic #18; //Method printClass:(Ljava/lang/Object;)V
7: aload_1
8: invokestatic #22; //Method callPrintClass:(Ljava/lang/Object;)V
11: iconst_1
12: anewarray #25; //class java/lang/String
15: dup
16: iconst_0
17: aload_1
18: aastore
19: invokestatic #27; //Method printClassVarargs:([Ljava/lang/Object;)V
22: aload_1
23: invokestatic #31; //Method callPrintClassVarargs:(Ljava/lang/Object;)V
26: return
public static void printClass(java.lang.Object);
Code:
0: getstatic #40; //Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokevirtual #46; //Method java/lang/Object.getClass:()Ljava/lang/Class;
7: invokevirtual #50; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
10: return
public static void printClassVarargs(java.lang.Object[]);
Code:
0: getstatic #40; //Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokevirtual #46; //Method java/lang/Object.getClass:()Ljava/lang/Class;
7: invokevirtual #59; //Method java/lang/Class.getComponentType:()Ljava/lang/Class;
10: invokevirtual #50; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
13: return
public static void callPrintClass(java.lang.Object);
Code:
0: aload_0
1: invokestatic #18; //Method printClass:(Ljava/lang/Object;)V
4: return
public static void callPrintClassVarargs(java.lang.Object);
Code:
0: iconst_1
1: anewarray #3; //class java/lang/Object
4: dup
5: iconst_0
6: aload_0
7: aastore
8: invokestatic #27; //Method printClassVarargs:([Ljava/lang/Object;)V
11: return
}
公共测试();
代码:
0:aload_0
1:特别是#8//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:ldc#16//字符串5318008
2:astore_1
3:aload_1
4:invokestatic#18//方法printClass:(Ljava/lang/Object;)V
7:aload_1
8:invokestatic#22//方法callPrintClass:(Ljava/lang/Object;)V
11:iconst_1
12:anewarray#25//类java/lang/String
15:dup
16:iconst_0
17:aload_1
18:aastore
19:invokestatic#27//方法printclassvargs:([Ljava/lang/Object;)V
22:aload_1
23:invokestatic#31;//方法callPrintClassVarargs:(Ljava/lang/Object;)V
26:返回
公共静态void打印类(java.lang.Object);
代码:
0:getstatic#40;//字段java/lang/System.out:Ljava/io/PrintStream;
3:aload_0
4:invokevirtual#46;//方法java/lang/Object.getClass:()Ljava/lang/Class;
7:invokevirtual#50;//方法java/io/PrintStream.println:(Ljava/lang/Object;)V
10:返回
公共静态void printclassvargs(java.lang.Object[]);
代码:
0:getstatic#40;//字段java/lang/System.out:Ljava/io/PrintStream;
3:aload_0
4:invokevirtual#46;//方法java/lang/Object.getClass:()Ljava/lang/Class;
7:invokevirtual#59;//方法java/lang/Class.getComponentType:()Ljava/lang/Class;
10:invokevirtual#50;//方法java/io/PrintStream.println:(Ljava/lang/Object;)V
13:返回
公共静态void callPrintClass(java.lang.Object);
代码:
0:aload_0
1:invokestatic#18;//方法printClass:(Ljava/lang/Object;)V
4:返回
公共静态void callPrintClassVarargs(java.lang.Object);
代码:
0:iconst_1
1:anewarray#3;//类java/lang/Object
4:dup
5:iconst_0
6:aload_0
7:aastore
8:invokestatic#27;//方法printClassVarargs:([Ljava/lang/Object;)V
11:返回
}
在main#12上观察字符串obj i的新字符串[]