Java通用高级用法

时间:2015-02-26 09:41:44

标签: java generics java-8 generic-programming

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

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),但没有运气。

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

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

3 个答案:

答案 0 :(得分:4)

问题是您希望finder的{​​{1}}方法是通用的。

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

apply

如果这被视为“助手类”,那么我不知道该告诉你什么。你正试图将一个方形钉子钉在圆孔上。 @FunctionalInterface interface Finder { <T> T apply(Map<T, T> map); } private static String fun(Finder finder) { // same body } 不是通用方法,因此您无法使用Function#apply执行此操作。

答案 1 :(得分:2)

您要使用方法fun尝试实现什么目标?

您使用通配符或类型参数Function传递T,然后您想将其应用于两种不同的具体类型(IntegerString )。

这不起作用:

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

因为您希望finder采用类型Integer,但您在fun声明中指定了类型未知(如果您使用{{ 1}})或某些无界类型?(如果使用类型参数T声明它)。但是,如果您要将其应用于T,那么对于某些无界类型Integer,您需要Function<Map<Integer, Integer>>,而不是Function<Map<?, ?>, ?>Function<Map<T, T>, T>

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

fun

答案 2 :(得分:2)

你可以这样做:

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