Java 通用高级用法

Java Generic Advanced Usage

问题是,如果泛型签名由多个相同类型的?组成,则以下代码无法编译。

import java.util.Map;
import java.util.HashMap;
import java.util.function.Function;

public class Test {

    private static <T> T findSelfReference(Map<T, T> map) {
        for (Map.Entry<T, T> entry : map.entrySet()) {
            if (entry.getKey() == entry.getValue()) {
                return entry.getKey();
            }
        }
        return null;
    }

    private static <T> T findSelfReference2(Map<T, T> map) {
        for (T key : map.keySet()) {
            if (map.get(key) == key) {
                return key;
            }
        }
        return null;
    }

    // Question: How to write the method signature that can ensure compile-time type safety? Both the signatures fail to compile.

    // private static <T> String fun(Function<Map<T, T>, T> finder) {
    private static String fun(Function<Map<?, ?>, ?> finder) {
        Map<Integer, Integer> map1 = new HashMap<>();
        // some processing to map1
        Integer n = finder.apply(map1);  // usage here, compile-time type checking wanted

        Map<String, String> map2 = new HashMap<>();
        // other processing to map2 depending on n
        return finder.apply(finder, map2);  // another usage
    }

    public static void main(String[] args) {
        // Please don't change into helper class...
        System.out.println(fun(Test::findSelfReference));
        System.out.println(fun(Test::findSelfReference2));
    }
}

fun 中,在对 finder.apply() 的每次调用中,类型 T 是固定的。但是在不同的呼叫中,他们使用不同的类型。我尝试了通配符捕获(参考:here)但没有成功。

我不想将结果转换为必须在运行时进行检查的对象。所有类型检查都应该在编译时完成。

是否可以不制作 O(n) 辅助程序类 其中 n 是内联函数的数量?

您究竟想用您的方法实现什么 fun

你用通配符或类型参数 T 向它传递 Function,然后你想将它应用于两种不同的具体类型(IntegerString).

这行不通:

Map<Integer, Integer> map1 = new HashMap<>();
// ...
Integer n = finder.apply(map1);

因为在这里你希望 finder 接受类型 Integer,但是你在 fun 的声明中指定了类型未知(如果你用?) 或一些无界类型 T (如果你用类型参数 T 声明它)。但是如果你要将它应用到 Integer 你需要一个 Function<Map<Integer, Integer>>,而不是 Function<Map<?, ?>, ?>Function<Map<T, T>, T> 对于一些无界类型 T.

你可以这样写 - 但是方法 fun 本身或多或少是没用的。

private static <T> T fun(Map<T, T> map, Function<Map<T, T>, T> finder) {
    return finder.apply(map);
}

public static void main(String[] args) {
    Map<Integer, Integer> map1 = new HashMap<>();
    map1.put(1, 2);
    map1.put(3, 4);
    map1.put(5, 7);
    map1.put(2, 2);
    map1.put(8, 8);
    Integer n = fun(map1, Test::findSelfReference);

    String a = String.valueOf(n + 1);
    Map<String, String> map2 = new HashMap<>();
    map2.put("1", "2");
    map2.put("3", "4");
    map2.put("5", "7");
    map2.put("3", a);
    String s = fun(map2, Test::findSelfReference2);

    System.out.println(n);
    System.out.println(s);
}

你可以这样做:

private static <T> T fun(Function<Map<T, T>, T> finder, Map<T, T> map) {
    return finder.apply(map);
}

private static Map<String, String> getStringMap(Integer n) {
    String a = String.valueOf(n + 1);
    Map<String, String> map2 = new HashMap<>();
    map2.put("1", "2");
    map2.put("3", "4");
    map2.put("5", "7");
    map2.put("3", a);
    return map2;
}

private static Map<Integer, Integer> getIntMap() {
    Map<Integer, Integer> map1 = new HashMap<>();
    map1.put(1, 2);
    map1.put(3, 4);
    map1.put(5, 7);
    map1.put(2, 2);
    map1.put(8, 8);
    return map1;
}

public static void main(String[] args) {
    fun(Test::findSelfReference, getIntMap());
    fun(Test::findSelfReference, getStringMap(1));
}

我不明白 fun 方法的目的,当您总是可以这样做时:

Function<Map<Integer, Integer>, Integer> m = Test::findSelfReference;
m.apply(getIntMap());

问题是您希望 finderapply 方法是通用的。

解决方案是使用泛型方法定义您自己的功能接口。

@FunctionalInterface
interface Finder {
    <T> T apply(Map<T, T> map);
}

private static String fun(Finder finder) {
    // same body
}

如果这算作 "helper class" 那么我不知道该告诉你什么。你正试图将一个方形的钉子敲入一个圆孔中。 Function#apply 不是通用方法,因此您不能使用 Function.