java - Java 9 中类型推断检查的变化

标签 java generics type-inference java-9

代码(缩短了实际代码以解释问题)。

import java.util.Map;
import java.util.HashMap;

public class TypeReferenceTest {

    public static  class Model {
        public void setAbc(Abc<String> abc) { }
    }

    public static class Abc<T> {
        public Abc(T val) { }
    }

    public static void main(String[] args) {
        Map<String, Object> attrMap = new HashMap<>();
        attrMap.put("key", 0);
        Model m = new Model ();
        m.setAbc(new Abc<>(getAttrOrDefault(attrMap, "key", "Default")));
        System.out.println("Test completed.....");
    }

    public static <T extends Object> T getAttrOrDefault(Map<String, Object> attrMap, String attrName, T defaultValue) {
        @SuppressWarnings("unchecked")
        T attrValue = (T)attrMap.get(attrName);
        return (attrValue == null) ? defaultValue : attrValue;
    }
}

测试

host:~/temp/test> /usr/local/java/jdk1.8/bin/javac TypeReferenceTest.java 
host:~/temp/test> file TypeReferenceTest.class 
TypeReferenceTest.class: compiled Java class data, version 52.0 (Java 1.8)
host:~/temp/test> /usr/local/java/jdk9/bin/java TypeReferenceTest
Test completed.....
host:~/temp/test> /usr/local/java/jdk9/bin/javac TypeReferenceTest.java 
host:~/temp/test> file TypeReferenceTest.class 
TypeReferenceTest.class: compiled Java class data, version 53.0
host:~/temp/test> /usr/local/java/jdk9/bin/java TypeReferenceTest
Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.Integer cannot be cast to java.base/java.lang.String
    at TypeReferenceTest.main(TypeReferenceTest.java:18)
host:~/temp/test> 

请注意在 Java 9 编译代码上运行相同代码时的异常。我理解代码导致 ClassCastException 的原因,但是如果代码是用 Java 8 编译的(两种情况下运行时都是 Java 9)就可以了。为了查看差异,我使用了 javap 并反汇编代码以查看差异。

Java 8 编译反汇编代码(这里只有感兴趣的部分)

  39: invokestatic  #11                 // Method getAttrOrDefault:(Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;

  42: invokespecial 

Java 9 编译反汇编代码(这里只是感兴趣的部分)

  39: invokestatic  #11                 // Method getAttrOrDefault:(Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
  42: checkcast     #12                 // class java/lang/String
  45: invokespecial 

注意到 Java 9 编译反汇编代码的差异,它在相关指令中明确检查类型。当然,从代码中应该很容易推断出返回类型应该是字符串,但之前没有明确检查。

问题:Java 9 中的类型推断和添加显式检查是否有一些变化?如果是,我在哪里可以找到详细信息(在变更日志中找不到)?是否在 Java 9 中更改了某些编译默认选项以在 Java 9 中添加此显式类型检查?

谢谢, 莫扎法尔

最佳答案

看起来这是 java-8 中的一个错误,很可能是 this one .它在 java-9 中得到修复。 checkcast必须在那里开始,因为你只需要 Abc<String>作为输入,在我看来。

关于java - Java 9 中类型推断检查的变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54181882/

相关文章:

java - 从 spring shell 中的少量选项中进行选择

java - Gradle /Maven : How to use in-developement dependencies?

java - 为什么这段通用代码会出现编译错误

generics - 引用具有原始类型约束的基本类型

Scala 类型推断和多参数列表

java - 如何在 Portlet 实例的所有用户之间共享数据?

java - Spring Boot @ResponseBody Jackson - 转义所有字符串字段

java - 自动装箱不适用于参数化类型

java - 如何将这种鸭子类型(duck typing)(Python)转换为 Java 泛型?

Scala 没有推断出适当的方法