简体   繁体   English

我如何使这个Java 7兼容?

[英]How would I make this Java 7 compatible?

I have an interface that basically looks like this: 我有一个基本上看起来像这样的接口:

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();
    }
}

And then in another class I have a list of ISetting<?> 然后在另一个班级中我有一个ISetting<?>

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

And this all works perfectly! 这一切都完美无缺! However, the platform where I use my code doesn't support Java 8, so I have to use Java 7, and here's where the problems come. 但是,我使用我的代码的平台不支持Java 8,所以我必须使用Java 7,这就是问题所在。

If I set the Maven target to 1.7, like this in my pom.xml: 如果我将Maven目标设置为1.7,就像在我的pom.xml中一样:

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

Then the code compiles perfectly with no errors or anything. 然后代码完美编译,没有错误或任何东西。 However, when I try to run the code, it gives me this error: 但是,当我尝试运行代码时,它给了我这个错误:

java.lang.ClassFormatError: Method getValueName in class net/uniqraft/murder/match/settings/ISetting has illegal modifiers: 0x1 java.lang.ClassFormatError:类net / uniqraft / murder / match / settings / ISetting中的方法getValueName具有非法修饰符:0x1

I tried to Google it but couldn't find anything that I understood or seemed to be applicable in my case. 我尝试谷歌它但找不到我理解或似乎适用于我的情况。

So, I thought, I'll just make the entire codebase into Java 7: 所以,我想,我只是将整个代码库变成Java 7:

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

The first error I see is: 我看到的第一个错误是:

Default methods are allowed only at source level 1.8 or above 仅在源级别1.8或更高级别允许默认方法

Which is incredibly annoying and I don't know how to bypass that. 这令人难以置信的烦恼,我不知道如何绕过它。 A lot of my code is dependent on default implementations. 我的很多代码都依赖于默认实现。 I guess I just have to use abstract classes instead? 我想我只需要使用抽象类代替?

But the more problematic error I see is on the List<Setting<?>> I have: 但是我看到的更有问题的错误是List<Setting<?>>我有:

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

I have no idea what that means or how to fix it. 我不知道这意味着什么或如何解决它。 The quickfix Eclipse offers are of no help. Eclipse提供的quickfix没有任何帮助。

In case the you need to see the full non-stripped ISetting class or the full stacktrace, I put them externally as they're rather spacey: 如果您需要查看完整的非剥离ISetting类或完整的堆栈跟踪,我将它们放在外部,因为它们相当宽敞:

I will divide the answer in two parts, the first regarding type inference and the second regarding default methods: 我将把答案分为两部分,第一部分是关于类型推断,第二部分是关于默认方法:

Type inference 类型推断

In Java 7, the type of an expression is the same, regardless of context . 在Java 7中, 无论上下文如何,表达式的类型都是相同的 So when you do: 所以当你这样做时:

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

It does not create a List<ISetting<?>> . 它不会创建List<ISetting<?>> You could make it work by changing the settings type to List<? extends ISetting<?>> 您可以通过将settings类型更改为List<? extends ISetting<?>>来使其工作List<? extends ISetting<?>> List<? extends ISetting<?>> . List<? extends ISetting<?>> That is, a list that can hold elements that can be a ISetting<?> or any subtype of it: 也就是说,一个列表可以包含可以是ISetting<?>或其任何子类型的元素:

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

In Java 8, assigning the resulting list to a List<ISetting<?>> works because of poly expressions . 在Java 8中,将结果列表分配给List<ISetting<?>>是因为List<ISetting<?>> 表达式 This means that the deduced type of some expressions can be influenced by the target type . 这意味着某些表达式的推导类型可能受目标类型的影响 So when you do: 所以当你这样做时:

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

The compiler analyses the target type and implicitly passes a type parameter to Arrays.asList() , which is equivalent to doing: 编译器分析目标类型并隐式地将类型参数传递给Arrays.asList() ,这相当于:

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

Which creates a List<ISetting<?>> and assigns it to settings . 这会创建一个List<ISetting<?>>并将其分配给settings The above form also works in Java 7, if you don't want to change the settings type. 如果您不想更改settings类型,上面的表单也适用于Java 7。

Default methods 默认方法

Java 7 does not have default methods. Java 7没有默认方法。 Instead, you could create an abstract skeletal implementation to go together with your interface. 相反,您可以创建一个抽象的骨架实现来与您的界面一起使用。 The interface will define the type, and the skeletal implementation will provide the default functionality. 接口将定义类型,骨架实现将提供默认功能。

First, turn the default methods in your interface into regular method declarations: 首先,将接口中的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.
}

Then create an abstract class to hold the default implementations: 然后创建一个抽象类来保存默认实现:

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.
}

Now make your concrete classes implement the ISetting<T> interface and extend the AbstractSetting<T> class. 现在让您的具体类实现ISetting<T>接口并扩展AbstractSetting<T>类。 For example: 例如:

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

You need to do one of the following: 您需要执行以下操作之一:

  • remove default modifier from getValueName() getValueName()删除默认修饰符
  • make [abstract] class instead of interface make [abstract]类而不是interface
  • upgrade your platform to Java 1.8 将您的平台升级到Java 1.8

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

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