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

Ian*_*edv 11 java eclipse generics java-8 long-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 + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

随着一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这背后的想法是能够定义一组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>();
}
Run Code Online (Sandbox Code Playgroud)

然后,将这些变量添加到实例中InputCollection,而实例又由许多"状态"或"进程"共享.Input<E>然后可以通过不同的状态更改a 的值,然后在原始状态需要时检索.一种共享内存模型.

这个概念已经运行了好几年(是的,这是遗留的),但我们最近开始转向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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

addding [null] to collection
addding [null] to collection
Input is: 1
Run Code Online (Sandbox Code Playgroud)

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

long longValue = collection.getValue(Input.INTEGER_ONE, -1);
Run Code Online (Sandbox Code Playgroud)

但是如果我访问这个值:

long longVal = Input.INTEGER_ONE.getValue();
Run Code Online (Sandbox Code Playgroud)

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

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

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

我读了 如何在Java中从int转换为Long? 并将 整数转换为Long,但并没有真正得到满意的答案.

Vla*_*lad 8

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

5.1.2.扩大原始转换

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

[..]

  • int到long,float或double

[..]

5.1.8.拆箱转换

[..]

  • 从类型Integer到类型int

发生的事情是从拆箱Integerint,然后不断扩大的转换long.这实际上正如Oracle JDK(1.8.0.25)中所期望的那样发生.

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

  • 这似乎在Eclipse Mars 4.5.0中得到修复 (2认同)

Pet*_*ček 6

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

已在Eclipse 4.5 M3中修复.