Java F-Bound types with generics

2019-05-31 22:16发布

问题:

Is there any way to express f-bound types in java where at the call site, a generic response is returned?

interface Functor<T extends Functor<T>>
  public <B> T<B> map(Function<A, B> fn); // won't compile because types don't match

I can use f-bound types if the type never changes, but in the case of map, I need a new type. Is there a way to express this in java?

What I am really looking for is any way that I can get something like higher kinds even though I know javac doesn't support higher kinded types.

Lets say we have a List<A> and want this interface to return a List<B>. But don't want this interface to know anything about List.

回答1:

Reading the Wikipedia definition of functor, it sounds like you want to define a generic type which is able to map from one category (Java type) to another. In your example above, to map from a List<A> to List<B> where the types A and B are generic.

If this is your aim, then consider the following interface for the definition of a Functor type:

public interface Functor<CategoryA, CategoryB> {
    public CategoryB map(CategoryA instance);
}

This declares that the Functor type deals in two generic parameter types, CategoryA and CategoryB and no constraints are put on these parameter types. It also declares that a method map must be implemented which maps from an object of type CategoryA to an object of type CategoryB.

Suppose, based on your example, you now want to create a concrete instance of a Functor which maps from List<Integer> to List<String>. You might create the following class:

public class IntegerListToStringList implements Functor<List<Integer>, List<String>> {
    @Override
    public List<String> map(List<Integer> integerList) {
        List<String> stringList = new ArrayList<>(integerList.size());
        for(Integer intValue : integerList) {
            stringList.add(Integer.toString(intValue));
        }
        return stringList;
    }
}

You could then invoke this concrete Functor implementation like so:

Functor<List<Integer>, List<String>> functor = new IntegerListToStringList();
Integer[] intArray = new Integer[] {2, 3, 5, 7, 11, 13};
List<Integer> intList = Arrays.asList(intArray);
List<String> stringList = functor.map(intList);
System.out.println("String list: " + stringList);

Now any method which is expecting a parameter of type Functor<List<Integer>, List<String>> can accept an instance of type IntegerListToStringList.