问题 Java 8 - 将Integer转换为长编译问题


我的项目中有以下抽象通用数据持有者(简化):

public abstract static class Value<E> {

    E value;

    public void setValue(E value) {
        this.value = value;
    }

    public E getValue() {
        return this.value;
    }

    public String toString() {
        return "[" + value + "]";
    }
}

随着一个 InputCollection 其中包含一个列表 Objects

public static class InputCollection {

    private ArrayList<Object> values;

    public InputCollection() {
        this.values = new ArrayList<>();
    }

    public void addValue(Value<?> value) {
        System.out.println("addding " + value + " to collection");
        this.values.add(value);
    }

    public <D> D getValue(Value<D> value, D defaultValue) {
        int index = this.values.indexOf(value);
        if (index == -1) 
            return defaultValue;

        Object val = this.values.get(index);
        if (val == null) {
            return defaultValue;
        }

        return ((Value<D>)val).getValue();
    }
}

这背后的想法是能够定义一组 final 实现这一点的变量 abstract  Value<E> 在所谓的“状态”中,如下所示:

public static final class Input<E> extends Value<E> {
    public static final Input<String> STRING_ONE = new Input<String>();
    public static final Input<Integer> INTEGER_ONE = new Input<Integer>();
}

然后,将这些变量添加到实例中 InputCollection而这又被许多“州”或“过程”所共享。一个人的价值 Input<E> 然后可以通过不同的状态进行更改,然后在原始状态需要时进行检索。一种共享内存模型。

这个概念已经运行了很多年(是的,这是遗留的),但我们最近开始转向Java 8,这创建了编译错误,即使实现在Java 7上工作。

添加以下内容 main 以上代码示例:

public static void main (String [] args) {

    InputCollection collection = new InputCollection();
    //Add input to collection
    collection.addValue(Input.STRING_ONE);
    collection.addValue(Input.INTEGER_ONE);

    //At some later stage the values are set
    Input.INTEGER_ONE.setValue(1);
    Input.STRING_ONE.setValue("one");

    //Original values are then accessed later
    long longValue = collection.getValue(Input.INTEGER_ONE, -1);

    if (longValue == -1) {
        System.out.println("Error: input not set");
    } else { 
        System.out.println("Input is: " + longValue);
    }
}

如果eclipse中的Compiler Compliance级别设置为1.7,则没有编译问题,输出将正确:

addding [null] to collection
addding [null] to collection
Input is: 1

但如果将其设置为1.8编译错误 Type mismatch: cannot convert from Integer to long 在线上

long longValue = collection.getValue(Input.INTEGER_ONE, -1);

但是,如果我访问这个值:

long longVal = Input.INTEGER_ONE.getValue();

没有编译问题,这令人困惑。

它可以通过强制转换来解决,但这在整个项目中都会使用,并且需要进行相当多的强制性测试才能更改每次出现。

Java 8中需要演员的变化是什么?编译是否变得更加严格?如果值是直接访问而不是通过集合,编译器为什么不抱怨呢?

我读 如何在Java中从int转换为Long?将整数转换为长整数 ,但我的问题并没有得到令人满意的答案。


7058
2017-11-24 12:50


起源

你能尝试编译吗? javac?我也有这个问题,我相信这是一个日食错误。如果我在我的代码中添加了强制转换,它会发出“不必要的强制转换”警告..​​.... :) - Petr Janeček
我无法在我的机器上复制。它在我的Java8中运行得非常好。 - Jatin
这实际上是Eclipse内部编译器中的一个错误。注意:Eclipse不使用 javac 来自已安装的JDK的命令,但使用内部编译器。此编译器报告错误。使用JDK工具编译它可以正常工作。 - Seelenvirtuose
我现在看到正在编译 javac 报告没有错误。那必须是日食。 - Ian2thedv
似乎与中的问题相同 stackoverflow.com/questions/25958687/... (也没有答案,但链接到 bugs.eclipse.org/bugs/show_bug.cgi?id=440019 ...可能还有关系: stackoverflow.com/questions/5385743/... ) - Marco13


答案:


根据 JLS for Java 8 这不应该发生:

5.1.2。扩大原始转换

对原始类型的19个特定转换称为扩展原始转换:

[..]

  • int到long,float或double

[..]

5.1.8。拆箱转换

[..]

  • 从类型Integer到int类型

应该发生什么是取消装箱 Integer 至 int,然后扩大转换为 long。这实际上正如Oracle JDK(1.8.0.25)中所期望的那样发生。

我相信你在JDK中遇到了一个编译器错误。您应该尝试更新版本或向维护者提交错误。


8
2017-11-24 13:34



你是对的。运用 javac 从JDK工作得很好。它似乎是Eclipse编译器中的一个错误。 - Seelenvirtuose
这似乎在Eclipse Mars 4.5.0中得到修复 - Ian2thedv


一个已知的Eclipse bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=440019

在Eclipse 4.5 M3中修复。


6
2017-11-26 01:29



希望我有办法在STS 3.6中获得修复..是吗? - jayP
我不知道。我只是下载了新版本,没关系。但是,是的,我可以想象一个你不想升级(或不能)的设置。尝试联系某人的某些人。 - Petr Janeček