我如何使 Java 7 兼容?

How would I make this Java 7 compatible?

我的界面基本上是这样的:

public interface ISetting<T> {
    public T getDefault();
    public T value();
    public void set(T value);
    public String getName();

    public default String getValueName() {
        Object obj = value();
        if (obj instanceof Boolean) {
            return (boolean)obj ? "Yes" : "No"; 
        }

        return obj.toString();
    }
}

然后在另一个 class 我有一个 ISetting<?>

的列表
private List<ISetting<?>> settings = Arrays.asList(
        new ClassMode(),
        new EndMode(),
        new PlayerLives(),
        new JoinMidGame(),
        new ScoreboardDisplay(),
        new LifePerKill(),
        new ExplosiveBullets(),
        new ReloadTime());

这一切都很完美!但是,我使用我的代码的平台不支持Java 8,所以我不得不使用Java 7,这就是问题所在。

如果我将 Maven 目标设置为 1.7,就像在我的 pom.xml 中这样:

<configuration>
    <source>1.8</source>
    <target>1.7</target>
</configuration>

然后代码可以完美编译,没有任何错误。但是,当我尝试 运行 代码时,它给了我这个错误:

java.lang.ClassFormatError: Method getValueName in class net/uniqraft/murder/match/settings/ISetting has illegal modifiers: 0x1

我尝试 Google 它但找不到我理解或似乎适用于我的情况的任何内容。

所以,我想,我会把整个代码库变成 Java 7:

<configuration>
    <source>1.7</source>
    <target>1.7</target>
</configuration>

我看到的第一个错误是:

Default methods are allowed only at source level 1.8 or above

这非常烦人,我不知道如何绕过它。我的很多代码都依赖于默认实现。我想我只需要使用抽象 classes 代替?

但我看到的问题更多的错误是 List<Setting<?>> 我有:

Type mismatch: cannot convert from List<ISetting<? extends Object&Comparable<?>&Serializable>> to List<ISetting<?>>

我不知道这意味着什么或如何修复它。 Eclipse 提供的 quickfix 没有帮助。

如果您需要查看完整的未剥离的 ISetting class 或完整的堆栈跟踪,我将它们放在外部,因为它们相当宽敞:

您需要执行以下操作之一:

  • getValueName()
  • 中删除默认修饰符
  • 制作[抽象]class而不是界面
  • 将您的平台升级到 Java 1.8

我将把答案分为两部分,第一部分关于类型推断,第二部分关于默认方法:

类型推断

在Java 7 中,无论上下文如何,表达式的类型都是相同的。所以当你这样做时:

Arrays.asList(new ClassMode(), new EndMode(), ...);

它不会创建 List<ISetting<?>>。您可以通过将 settings 类型更改为 List<? extends ISetting<?>> 来使其工作。也就是说,一个列表可以包含可以是 ISetting<?> 或其任何子类型的元素:

List<? extends ISetting<?>> settings = Arrays.asList(new ClassMode(), new EndMode(), ...);

在 Java 8 中,由于 poly expressions,将结果列表分配给 List<ISetting<?>> 是可行的。这意味着某些表达式的推导类型会受到目标类型的影响。所以当你这样做时:

private List<ISetting<?>> settings = Arrays.asList(new ClassMode(), new EndMode(), ...);

编译器分析目标类型并隐式传递一个类型参数给Arrays.asList(),相当于做:

private List<ISetting<?>> settings = Arrays.<ISetting<?>>asList(new ClassMode(), new EndMode(), ...);

创建一个 List<ISetting<?>> 并将其分配给 settings。如果您不想更改 settings 类型,上述形式在 Java 7 中也有效。

默认方法

Java 7 没有默认方法。相反,您可以创建一个抽象 骨架实现 来与您的界面一起使用。接口将定义类型,骨架实现将提供默认功能。

首先,将接口中的 default 方法转换为常规方法声明:

public interface ISetting<T> {
    T getDefault();
    T value();
    void set(T value);
    String getName();

    // Former default methods:
    String getValueName();
    boolean isHidden();
    boolean isDefault();
    // etc.
}

然后创建一个抽象 class 来保存默认实现:

public abstract class AbstractSetting<T> implements ISetting<T> {

    @Override
    public String getValueName() {
        Object obj = value();
        if (obj instanceof Boolean) {
            return ((Boolean) obj) ? "Yes" : "No";
        }
        return obj.toString();
    }

    @Override
    public boolean isHidden() {
        return false;
    }

    // etc.
}

现在让您的具体 classes 实现 ISetting<T> 接口并扩展 AbstractSetting<T> class。例如:

public class ConcreteSetting extends AbstractSetting<Boolean> implements ISetting<Boolean> {
    // concrete implementation
}