Home > Mobile >  Java generic parametrized parameter constrained by other parameters
Java generic parametrized parameter constrained by other parameters

Time:10-21

I have a generic class, which has a function that returns an instance of a functional interface:

/**
 * @param <FF> - FF is a functional interface
 */
public abstract class MyFunctionalInterfaceGetter<FF> {
    public abstract <PC, AC> FF getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass);
}

And I have a couple of derived classes:

public class MyGetterGetter extends MyFunctionalInterfaceGetter<java.util.function.Function> {
    public <PC, AC> Function<PC, AC> getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass) {
         ...
    }
}
public class MySetterGetter extends MyFunctionalInterfaceGetter<java.util.function.BiConsumer> {
    public <PC, AC> BiConsumer<PC, AC> getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass) {
         ...
    }
}

And the question:
I do not thing so, but I wanted to know if there is any way to constrain the returning parametrized type from the function parameters at the parent class.
Something like this:

public abstract class MyFunctionalInterfaceGetter<FF> {
    public abstract <PC, AC> FF<PC, AC> getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass);
}

I am using Java-8

CodePudding user response:

Bounded Type Parameters
There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.

To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in this example is Number. Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces).

public class Box<T> {

    private T t;          

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public <U extends Number> void inspect(U u){
        System.out.println("T: "   t.getClass().getName());
        System.out.println("U: "   u.getClass().getName());
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        integerBox.set(new Integer(10));
        integerBox.inspect("some text"); // error: this is still String!
    }
}
By modifying our generic method to include this bounded type parameter, compilation will now fail, since our invocation of inspect still includes a String:

Box.java:21: <U>inspect(U) in Box<java.lang.Integer> cannot
  be applied to (java.lang.String)
                        integerBox.inspect("10");
                                  ^
1 error
In addition to limiting the types you can use to instantiate a generic type, bounded type parameters allow you to invoke methods defined in the bounds:

public class NaturalNumber<T extends Integer> {

    private T n;

    public NaturalNumber(T n)  { this.n = n; }

    public boolean isEven() {
        return n.intValue() % 2 == 0;
    }

    // ...
}
The isEven method invokes the intValue method defined in the Integer class through n.

Multiple Bounds
The preceding example illustrates the use of a type parameter with a single bound, but a type parameter can have multiple bounds:

<T extends B1 & B2 & B3>
A type variable with multiple bounds is a subtype of all the types listed in the bound. If one of the bounds is a class, it must be specified first. For example:

Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }

class D <T extends A & B & C> { /* ... */ }
If bound A is not specified first, you get a compile-time error:

class D <T extends B & A & C> { /* ... */ }  // compile-time error

CodePudding user response:

Move the generics to the class level and apply if to its subtypes:

public abstract static class MyFunctionalInterfaceGetter<FF, PC, AC> {
    public abstract FF getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass);
}
public static class MyGetterGetter<PC, AC> extends MyFunctionalInterfaceGetter<Function<PC, AC>, PC, AC> {

    @Override
    public Function<PC, AC> getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass) {
        ...
    }
}
public static class MySetterGetter<PC, AC> extends MyFunctionalInterfaceGetter<BiConsumer<PC, AC>, PC, AC> {

    @Override
    public BiConsumer<PC, AC> getMyFunction(Class<PC> pojoClass, Class<AC> attributeClass) {
        ...
    }
}
  • Related