【问题标题】:Changes around type inference check in Java 9Java 9 中类型推断检查的变化
【发布时间】:2019-01-14 12:49:33
【问题描述】:

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

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 中添加了此显式类型检查吗?

谢谢, 莫扎法尔

【问题讨论】:

  • 听起来你想禁用类型检查。为什么?实际执行代码的静态类型的代码有什么问题?写出有效的代码,就没有问题了。
  • @Andreas 听起来你想禁用类型检查。为什么? - 我不想,这是一个很好的检查,但是一段代码突然开始导致异常。我的问题是在哪里可以找到 Java 9 中与此更改相关的更改日志,以及可能有关更多此类更改的信息。
  • 您应该在代码库中搜索可疑的@SuppressWarnings("unchecked") 事件,而不是在更改日志中搜索影响难以预测的内容(不查看特定的源代码,这会让您回到首选解决方案)。顺便把方法简化为return attrMap.getOrDefault(attrName, defaultValue);
  • @Holger 现有的旧代码可以更改和改进,但我相信只需将该方法更改为return attrMap.getOrDefault(attrName, defaultValue); 就会改变这里的现有行为。

标签: java generics type-inference java-9


【解决方案1】:

看起来这是 java-8 中的一个错误,很可能是this one。它在 java-9 中得到了修复。在我看来,checkcast 必须从那里开始,因为您只将Abc&lt;String&gt; 作为输入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-18
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多