Java 8不兼容的类型 [英] Java 8 Incompatible Types

查看:716
本文介绍了Java 8不兼容的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是简单的代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class SimpleTest {

    public static void main(String[] args) {
    final ArrayList<Map<String, Object>> maps = newArrayList(
        createMap("1", "a", Collections.EMPTY_MAP, Collections.EMPTY_MAP),
        createMap("2", "b", Collections.EMPTY_MAP, Collections.EMPTY_MAP),
        createMap("3", "c", Collections.EMPTY_MAP, Collections.EMPTY_MAP)
    ); 

    System.out.println(" maps = " + maps);
    }

    public static Map<String, Object> createMap(String value1, String value2, Map<String, Object> object1, Map<String, Object> object2) {
       Map<String, Object> map = new HashMap<>();
       map.put("value1", value1);
       map.put("value1", value1);
       map.put("object1", object1);
       map.put("object2", object2);
       return map;
    }    

    public static <E> ArrayList<E> newArrayList(E... elements) {
    ArrayList<E> list = new ArrayList<E>(elements.length);
    Collections.addAll(list, elements);
    return list;
    }
}

当JAVA_HOME指向JDK 8并且我使用 javac -source 1.7 SimpleTest.java 我得到

When JAVA_HOME points to JDK 8 and I use javac -source 1.7 SimpleTest.java I get

SimpleTest.java:9: error: incompatible types: ArrayList<Map> cannot be converted to ArrayList<Map<String,Object>>
        final ArrayList<Map<String, Object>> maps = newArrayList(
                                                                ^

当我使用 -source 1.8时或没有 -source 选项一切正常。现在,当JAVA_HOME指向JDK 7时,代码总是编译我是否使用 -source 1.7 或不。

When I use -source 1.8 or no -source option everything works ok. Now, when JAVA_HOME points to JDK 7 the code always compiles whether I use -source 1.7 or not.

最初这个问题是关于一个软件,其中POM文件有<源> < target> 设置为 1.7 并且JDK上的构建失败8但在JDK 7上没问题。

Initially this question was about a piece of software where POM file has a <source> and <target> set to 1.7 and the build was failing on JDK 8 but was ok on JDK 7.

现在问题是什么导致它发生?在我看来这是一种主要的忽视。为什么要编译JDK 8 来源设置为 1.7 失败?

Now for the question - what causes it to happen ? It seems to me as a major overlook of some sort. Why compiling on JDK 8 with source set to 1.7 fails ?

推荐答案

您可以将代码简化为不需要第三方库的自包含示例:

You can simplify the code to a self-contained example which doesn’t need 3rd-party libraries:

public class Test2 {
    @SafeVarargs
    static <T> ArrayList<T> newArrayList(T... arg) {
        return new ArrayList<T>(Arrays.asList(arg));
    }
    private final List<Map<String, Object>> maps = newArrayList(
        createMap(null, Collections.EMPTY_MAP)
     );

    public static Map<String, Object> createMap(String id, Map<String,String> m) {
        return null;
    }
}

这可以使用进行编译来自jdk1.7的javac ,而不是来自jdk1.8的 javac 使用 -source 1.7

This can be compiled using javac from jdk1.7, but not with javac from jdk1.8 using -source 1.7.

这里的一点是来自jdk1.8的 javac 仍然是一个与包含在其中的编译器不同的编译器以前的版本和选项 -source 1.7 并没有告诉它模仿旧实现的行为,而是与Java 7 规范兼容。如果旧编译器有错误,则较新的编译器不必尝试重现该错误。

The point here is that javac from jdk1.8 still is a different compiler than the one included in the previous version and the option -source 1.7 doesn’t tell it to mimic the old implementation’s behavior but to be compatible with the Java 7 specification. If the old compiler has a bug, the newer compiler doesn’t have to try to reproduce the bug.

由于代码使用 Collections.EMPTY_MAP 而不是集合。< String,String> emptyMap(),原始类型地图将传递给 createMap ,使其成为未经检查的调用,其原始结果类型为 Map

Since the code uses Collections.EMPTY_MAP rather than Collections.<String,String>emptyMap(), the raw type Map will be passed to createMap, making it an unchecked invocation having the raw result type Map.

这是由JLS§15.12.2.6


所选方法的结果类型确定如下:

The result type of the chosen method is determined as follows:


  • 如果声明所选方法的返回类型为void,则结果为void。

  • If the chosen method is declared with a return type of void, then the result is void.

否则,如果该方法需要未经检查的转换,则结果类型是方法声明的返回类型的擦除(第4.6节)。

Otherwise, if unchecked conversion was necessary for the method to be applicable, then the result type is the erasure (§4.6) of the method's declared return type.

...

似乎这个行为还没有(完全)在 javac 的jdk1.7。有趣的是,它会在添加类型参数时正确执行,例如

It seems that this behavior has not been (fully) implemented in javac of jdk1.7. Interestingly, it will do it correctly when adding a type parameter like

public static <T> Map<String, Object> createMap(String id, Map<String,String> m)

使其成为通用方法。然后,jdk1.7将产生相同的错误。但引用的规则适用于所有方法调用。

making it a generic method. Then, jdk1.7 will produce the same error. But the cited rule applies to all method invocations.

相比之下,编译的事实它与Java 8合规性成功源于新的目标类型推断,它具有完全不同的规则。

In contrast, the fact that compiling it with Java 8 compliance succeeds stems from the new target type inference, which has entirely different rules.

这篇关于Java 8不兼容的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆