与通用签名接口的静态方法

时间:2017-11-22 08:57:19

标签: java generics interface static java-8

从Java 8开始,您可以在Interfaces中实现默认或静态方法,如下所示

public interface DbValuesEnumIface<ID, T extends Enum<T>> {
   T fromId(ID id);

   ID getId();
   static String getDescriptionKey(){
      return "this is a test";
   }
}

我想用静态方法声明上面的方法,该签名使用实现类定义的边界,因为方法的实现应该对所有人都是相同的,唯一不同的应该是声明的泛型,如下:

public interface DbValuesEnumIface<ID, T extends Enum<T>> {

   public static T fromId(ID id) {
        if (id == null) {
            return null;
        }
        for (T en : T.values()) {
            if (en.getId().equals(id)) {
                return en;
            }
        }
    }

    ID getId();

    String getDescriptionKey();
}
...
public enum Statuses implements DbValuesEnumIface<Integer,Statuses>

因为T和ID不是静态的而无法从静态上下文中引用而中断。

那么,如何修改上述内容以便成功编译,如果不可能,那么应该如何实现上述目标以实现预期目的,同时避免在实现类中实现代码重复。

3 个答案:

答案 0 :(得分:5)

由于static方法和类的类型参数(描述实例的参数化方式)之间没有关系,因此必须使static方法本身具有通用性。棘手的部分是使声明正确描述所有需要的约束。正如this answer已经解释过的那样,你需要一个Class参数,否则,实现没有机会得到实际的类型参数:

public interface DbValuesEnumIface<ID, T extends Enum<T>> {

   public static
   <ID, T extends Enum<T>&DbValuesEnumIface<ID,T>> T fromId(ID id, Class<T> type) {
        if (id == null) {
            return null;
        }
        for (T en : type.getEnumConstants()) {
            if (en.getId().equals(id)) {
                return en;
            }
        }
        throw new NoSuchElementException();
    }

    ID getId();

    String getDescriptionKey();
}

请注意,static方法的类型参数独立于类的类型参数。为清楚起见,您可以考虑给他们不同的名称。

现在,给您enum Statuses implements DbValuesEnumIface<Integer,Statuses>示例,您可以使用Statuses status = DbValuesEnumIface.fromId(42, Statuses.class);

等方法

请注意,对于default方法,可以访问实际类型,因为实现将提供method providing the enum type。您只需在interface

中声明方法的存在
public interface DbValuesEnumIface<ID, T extends Enum<T>&DbValuesEnumIface<ID,T>> {

    public default T fromId(ID id) {
        if (id == null) {
            return null;
        }
        for (T en : getDeclaringClass().getEnumConstants()) {
            if (en.getId().equals(id)) {
                return en;
            }
        }
        throw new NoSuchElementException();
    }
    Class<T> getDeclaringClass();//no needed to implement it, inherited by java.lang.Enum
    ID getId();
    String getDescriptionKey();
}

然而,明显的缺点是您需要一个目标实例来调用该方法,即Statuses status = Statuses.SOME_CONSTANT.fromId(42);

答案 1 :(得分:2)

据我所知,没有简单的方法,首先您需要将方法更改为default,您可以阅读更多here为什么您不能在静态上下文中使用泛型

但即使你把它改为default,事情仍然无法发挥作用,因为你需要将枚举的实例或类类型传递给该方法,如下所示:

public default T fromId(ID id, Class<T> t) {
        if (id == null) {
            return null;
        }
        for (T en : t.getEnumConstants()) {
            // dome something
        }
        return null;
}

现在你在fromId内遇到了另一个问题 - 你唯一知道的是T扩展了enum - 而不是你的枚举,因此getId (这似乎是你的枚举)编译器根本不知道。

除了声明界面之外,我不知道一个简单的方法来完成这项工作,例如:

interface IID {
    public int getId();
} 

enum实现它:

static enum My implements IID {
    A {

        @Override
        public int getId() {
            // TODO Auto-generated method stub
            return 0;
        }

    };
}

并将声明更改为:

public interface DbValuesEnumIface<ID, T extends Enum<My> & IID>

答案 2 :(得分:1)

您可以从static更改为default,它将成功编译。

default EvaluationStatuses fromId(Integer id)