Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static Method in Interface with Generic signature

As of Java 8 you can have default or static methods implemented in Interfaces as the below

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

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

I would like to declare the above with the static method having a signature that uses bounds defined by the implementing classes since the method's implementation should be the same for all,with the only thing different should be the generics declared, as such:

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>

which breaks because T and ID are not static and cant be referenced from a static context.

So, how should the above be modified to compile successfully and if thats not possible, how the above should be implemented to achieve the desired purpose while avoiding code duplication within implementing classes .

like image 242
Leon Avatar asked Nov 22 '17 08:11

Leon


People also ask

Can generics be used with static methods?

Static and non-static generic methods are allowed, as well as generic class constructors. The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type.

Can you have static methods in an interface?

Similar to Default Method in Interface, the static method in an interface can be defined in the interface, but cannot be overridden in Implementation Classes. To use a static method, Interface name should be instantiated with it, as it is a part of the Interface only.

Why static method is not allowed in interface?

This is because it's not allowed in java, since Object is the base class for all the classes and we can't have one class level static method and another instance method with same signature.

What is static method signature?

Static method definition. The first line of a static method definition, known as the signature, gives a name to the method and to each parameter variable. It also specifies the type of each parameter variable and the return type of the method. Following the signature is the body of the method, enclosed in curly braces.


1 Answers

Since there is no relationship between static methods and the class’ type parameters, which describe how instances are parameterized, you have to make the static method generic on its own. The tricky part is to get the declarations right to describe all needed constraints. And as this answer already explained, you need to a a Class parameter, as otherwise, the implementation has no chance to get hands on the actual type arguments:

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

Note that the type parameters of the static method are independent from the class’ type parameter. You may consider giving them different names for clarity.

So now, given you enum Statuses implements DbValuesEnumIface<Integer,Statuses> example, you can use the method like Statuses status = DbValuesEnumIface.fromId(42, Statuses.class);


Note that for default methods, it is possible to access the actual type, as a method providing the enum type will be provided by the implementation. You only have to declare the presence of the method within the 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();
}

However, the obvious disadvantage is that you need a target instance to invoke the method, i.e. Statuses status = Statuses.SOME_CONSTANT.fromId(42);

like image 96
Holger Avatar answered Oct 02 '22 13:10

Holger