繁体   English   中英

在java 8中键入不匹配错误

[英]Type mismatch error in java 8

我有以下类使用以下方法。

public class MyClass {

    public static <T> T getSomeThing(final int id, final java.lang.reflect.Type type, final Map<Integer, String> someThings) {
        final String aThing = someThings.get(id);
        if (aThing == null || aThing.isEmpty()) {
            return null;
        }
        return GsonHelper.GSON.fromJson(aThing, type);
    }

}

GsonHelper为我提供了一些com.google.gson.GsonBuilder

public class GsonHelper {

    public static final com.google.gson.Gson GSON = getGsonBuilder().create();

    public static GsonBuilder getGsonBuilder() {
        return new GsonBuilder().setPrettyPrinting()
                .enableComplexMapKeySerialization()
                .registerTypeAdapter(new com.google.gson.reflect.TypeToken.TypeToken<byte[]>() {
                    // no body
                }.getType(), new Base64TypeAdapter())
                .registerTypeHierarchyAdapter(Date.class, new DateTypeAdapter())
                .registerTypeHierarchyAdapter(Pattern.class, new PatternTypeAdapter())
                .registerTypeAdapterFactory(new ListTypeAdapterFactory())
                .registerTypeAdapterFactory(new MapTypeAdapterFactory())
                .registerTypeAdapterFactory(new SetTypeAdapterFactory());
    }
}

在Java 7之前,我使用的方法如下:

Map<Integer, String> allThings = new HashMap<>();
//FILL allThings with values

if(MyClass.getSomeThing(7, java.lang.Boolean.class, allThings)){
    //do something
}

这很好。 因为该方法将返回一个布尔值,我可以在“if”里面使用它。 但是当我改为Java 8时,这是不可能的。 编译器抱怨:

类型不匹配:无法从Object转换为boolean

 //while this is working but would throw a JsonSyntaxException
final String myString = "myInvalidJsonString";
if(GsonHelper.GSON.fromJson(myString, java.lang.Boolean.class)){
    //do something
}

我知道java.lang.Boolean可以为null。 我可以用以下方法解决这个问题:

final Boolean b = MyClass.getSomeThing(7, java.lang.Boolean.class, allThings);
if(b){
    //do something
}

但我很好奇为什么这适用于Java 7而不是Java 8。 (未回答)
他们改变了什么? (无解答)
更改为Java 8时,此编译器错误的原因是什么? (回答)

您的方法public static <T> T getSomeThing(final int id, final java.lang.reflect.Type t, final Map<Integer, String> someThings)不保证返回Boolean 它返回由调用者定义的T ,可以是任何东西,也就是Object

if语句无法知道T将具有哪种类型,因此无法保证将其转换为布尔值。

为什么不将签名更改为布尔值?

public static boolean getSomeThing(final int id,
                                   final java.lang.reflect.Type t,
                                   final Map<Integer, String> someThings)

或者你在寻找这个?

public static <T> T getSomeThing(final int id,
                                 final Class<T> clazz,
                                 final Map<Integer, String> someThings)

比这段代码编译和工作:

public static void main(String[] args) {
    if (getSomeThing(7, Boolean.class, emptyMap())) {
        System.out.println("It works!");
    }
}

public static <T> T getSomeThing(final int id,
                                 final Class<T> clazz,
                                 final Map<Integer, String> someThings) {
    ...
}

可以根据JLS 8推断将getSomeThing()的结果分配给Boolean变量的最后一个版本,因为在赋值上下文中 ,目标类型Boolean确实将T推断为Boolean 这里所有编译器都同意。

关于原始情况,JLS 8不将if语句的条件分类为赋值上下文 在赋值或调用上下文之外,调用不被视为多表达式,而是作为独立表达式( JLS 15.12 1st bullet )。 独立表达式没有目标类型。 在Java 8中没有目标类型推断可以回退到推断TObject

Eclipse团队甚至在Java 8 GA之前就要求澄清这方面的内容 不幸的是, 由此产生的问题直到今天仍未得到解决。

Ergo:JLS和观察到的javac行为似乎并不一致。 可能,JLS是应该修复的实体。

更新: JLS不会更改(通过私人电子邮件确认),因此接受该程序是javac的错误。

编辑: Javac版本12将通过切换表达式传播此错误:

public class X {
    @SuppressWarnings("preview")
    public void foo(int i) {
        if (switch(i) { default -> magic(); })
            System.out.println("true");
    }
    <T> T magic() { return null; }
}

由于目标类型为Boolean类型推断,javac接受此操作,但在此位置执行类型推断对于每个JLS是非法的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM