Изменения в проверке вывода типов в Java 9 - PullRequest
0 голосов
/ 14 января 2019

Код (Сокращенный код для объяснения вопроса).

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;
    }
}

Test

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?

Спасибо, Mozaffar

1 Ответ

0 голосов
/ 14 января 2019

Похоже, что это была ошибка в java-8, наиболее вероятно эта . И это было исправлено в java-9. checkcast должно быть там с самого начала, так как, на мой взгляд, вы принимаете только Abc<String> в качестве входных данных.

...