Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java泛型;“向上投射”;非参数化类型_Java_Generics_Compilation_Jvm_Rtti - Fatal编程技术网

Java泛型;“向上投射”;非参数化类型

Java泛型;“向上投射”;非参数化类型,java,generics,compilation,jvm,rtti,Java,Generics,Compilation,Jvm,Rtti,为什么只有在取消对Main.Main()中的第三条语句的注释时才得到ClassCastException?没有例外,但执行良好的第一和第二条语句 public class Tuple<K, V> { public final K first; public final V second; public Tuple(K first, V second) { this.first = first; this.second = second; } @Ov

为什么只有在取消对Main.Main()中的第三条语句的注释时才得到ClassCastException?没有例外,但执行良好的第一和第二条语句

public class Tuple<K, V> {
    public final K first;
    public final V second;

public Tuple(K first, V second) {
    this.first = first;
    this.second = second;
}

@Override public String toString() {
    return "Tuple{" + "first = " + first + ", second = " + second + '}';
    }
}

class Test { static Tuple f(){return new Tuple("test", 8);} }

class Bar {}

class Main{
    public static void main(String[] args) {
        Tuple<String, Bar> t = Test.f();
        System.out.println(t);
      //System.out.println(t.second.getClass().getSimpleName());
    }
}
公共类元组{
公开决赛K第一;
公开决赛V秒;
公共元组(K第一,V第二){
this.first=first;
这个秒=秒;
}
@重写公共字符串toString(){
返回“Tuple{”+“first=“+first+”,second=“+second+'}”;
}
}
类测试{静态元组f(){返回新元组(“Test”,8);}
类条{}
班长{
公共静态void main(字符串[]args){
元组t=Test.f();
系统输出打印ln(t);
//System.out.println(t.second.getClass().getSimpleName());
}
}
提前感谢。

根据,对于
Object
类中的
getClass()
方法

根据,对于
对象中的
getClass()
方法,实际结果类型为


编写方法调用链时,实际结果类型为
类:

System.out.println(t.second.getClass().getSimpleName());
编译器有效地将其扩展为:

TypeOfTSecond tmpTSecond = t.second;
Class<?> clazzTmp = tmp.getClass();
String nameTmp = clazzTmp.getSimpleName();
System.out.println(nameTmp);
因此,即使您从未访问任何特定于
条的功能,您也会得到
ClassCastException


为了演示这一点,下面是字节码:

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2        // Method Test.f:()LTuple;
       3: astore_1
       4: getstatic     #3        // Field java/lang/System.out:Ljava/io/PrintStream;
       7: aload_1
       8: getfield      #4        // Field Tuple.second:Ljava/lang/Object;
      11: checkcast     #5        // class Bar
      14: invokevirtual #6        // Method java/lang/Object.getClass:()Ljava/lang/Class;
      17: invokevirtual #7        // Method java/lang/Class.getSimpleName:()Ljava/lang/String;
      20: invokevirtual #8        // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      23: return
第8行是将
t.second
推到堆栈上的位置;第11行是转换到
条的位置


这只是因为在声明
test.f()
时使用了原始类型:

如果这被正确地声明为

static Tuple<String, Integer> f(){return new Tuple<>("test", 8);}
当我重新编译该标志时:

Main.java:19: warning: [unchecked] unchecked call to Tuple(K,V) as a member of the raw type Tuple
      return new Tuple("test", 8);
             ^
  where K,V are type-variables:
    K extends Object declared in class Tuple
    V extends Object declared in class Tuple
Main.java:26: warning: [unchecked] unchecked conversion
    Tuple<String, Bar> t = Test.f();
                                 ^
  required: Tuple<String,Bar>
  found:    Tuple
2 warnings
Main.java:19:警告:[未选中]未选中对作为原始类型元组成员的元组(K,V)的调用
返回新元组(“test”,8);
^
其中K,V是类型变量:
扩展类元组中声明的对象
V扩展类元组中声明的对象
Main.java:26:警告:[未选中]未选中的转换
元组t=Test.f();
^
必需:元组
发现:元组
2警告

编写方法调用链时:

System.out.println(t.second.getClass().getSimpleName());
编译器有效地将其扩展为:

TypeOfTSecond tmpTSecond = t.second;
Class<?> clazzTmp = tmp.getClass();
String nameTmp = clazzTmp.getSimpleName();
System.out.println(nameTmp);
因此,即使您从未访问任何特定于
条的功能,您也会得到
ClassCastException


为了演示这一点,下面是字节码:

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2        // Method Test.f:()LTuple;
       3: astore_1
       4: getstatic     #3        // Field java/lang/System.out:Ljava/io/PrintStream;
       7: aload_1
       8: getfield      #4        // Field Tuple.second:Ljava/lang/Object;
      11: checkcast     #5        // class Bar
      14: invokevirtual #6        // Method java/lang/Object.getClass:()Ljava/lang/Class;
      17: invokevirtual #7        // Method java/lang/Class.getSimpleName:()Ljava/lang/String;
      20: invokevirtual #8        // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      23: return
第8行是将
t.second
推到堆栈上的位置;第11行是转换到
条的位置


这只是因为在声明
test.f()
时使用了原始类型:

如果这被正确地声明为

static Tuple<String, Integer> f(){return new Tuple<>("test", 8);}
当我重新编译该标志时:

Main.java:19: warning: [unchecked] unchecked call to Tuple(K,V) as a member of the raw type Tuple
      return new Tuple("test", 8);
             ^
  where K,V are type-variables:
    K extends Object declared in class Tuple
    V extends Object declared in class Tuple
Main.java:26: warning: [unchecked] unchecked conversion
    Tuple<String, Bar> t = Test.f();
                                 ^
  required: Tuple<String,Bar>
  found:    Tuple
2 warnings
Main.java:19:警告:[未选中]未选中对作为原始类型元组成员的元组(K,V)的调用
返回新元组(“test”,8);
^
其中K,V是类型变量:
扩展类元组中声明的对象
V扩展类元组中声明的对象
Main.java:26:警告:[未选中]未选中的转换
元组t=Test.f();
^
必需:元组
发现:元组
2警告

我的理解是,这在Java中不起作用。你的泛型没有被赋予类型,它们是泛型。如果您有类似于
public final K first的东西,那么这将起作用Test.f()
返回原始类型。如果避免使用原始类型,则更容易捕获此错误。
Test.f()
的返回类型应定义为
Tuple
,以匹配所返回的值。这将导致Tuple t=Test.f()上出现编译错误。
。类型安全是一个强大的功能。您应该发布完整的错误:
线程“main”java.lang.ClassCastException中的异常:java.lang.Integer无法转换为Bar
-现在它变得更清晰了…请阅读。我的理解是,这在java中不起作用。你的泛型没有被赋予类型,它们是泛型。如果您有类似于
public final K first的东西,那么这将起作用Test.f()
返回原始类型。如果避免使用原始类型,则更容易捕获此错误。
Test.f()
的返回类型应定义为
Tuple
,以匹配所返回的值。这将导致Tuple t=Test.f()上出现编译错误。
。类型安全是一个强大的功能。您应该发布完整的错误:
线程“main”java.lang.ClassCastException中的异常:java.lang.Integer无法转换为Bar
-现在它变得更清晰了…请阅读。注意,在这种情况下,编译器不需要将
t.second
转换为
Bar
。这取决于实现。请注意,在这种情况下,编译器不需要插入
t.second
Bar
的强制转换。也就是说,这样做依赖于实现。向下投票是没有用的,除非有一个向下投票的人澄清isI没有向下投票的问题,但我猜这是因为您的修复基于原始类型的使用。如果
Test.f()
声明的类型参数与返回的值相匹配(
),则使用
时会出现编译错误。虽然它可以工作,但它会鼓励糟糕的设计,因为它避免了实际问题(缺乏类型安全性),这通过您执行此操作时收到的警告消息显示出来。我个人不会因为这个原因投反对票(它仍然有效),但有些人比其他人更严格。我明白了!因此,在这里,我们不仅要提供修复并解释修复背后的原因,还必须提出最佳实践建议。正如你所说,我没有说不鼓励使用原始类型。谢谢确切地我个人觉得它不值得投反对票,因为它仍然有效,但如果答案鼓励更好的实践,我可能会投反对票。@VinceEmigh,我用附加注释更新了我的答案。如果不
Main.java:19: warning: [unchecked] unchecked call to Tuple(K,V) as a member of the raw type Tuple
      return new Tuple("test", 8);
             ^
  where K,V are type-variables:
    K extends Object declared in class Tuple
    V extends Object declared in class Tuple
Main.java:26: warning: [unchecked] unchecked conversion
    Tuple<String, Bar> t = Test.f();
                                 ^
  required: Tuple<String,Bar>
  found:    Tuple
2 warnings