代码之家  ›  专栏  ›  技术社区  ›  Leon

与泛型签名接口的静态方法

  •  12
  • Leon  · 技术社区  · 7 年前

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

    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 回复  |  直到 7 年前
        1
  •  7
  •   Holger    7 年前

    因为两者之间没有关系 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();
    }
    

    请注意 静止的 方法独立于类类型参数。为了清楚起见,你可以考虑给他们起不同的名字。

    那么现在,给你 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);

        2
  •  2
  •   Eugene    7 年前

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

    但即使你把它改成 违约 事情仍然无法进行,因为您需要将枚举的实例或类类型传递给该方法,如下所示:

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

    制作您的 枚举 实施它:

    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>
    
        3
  •  1
  •   fhery021    7 年前

    您可以从 static default 它将成功编译。

    default EvaluationStatuses fromId(Integer id)