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
,然后你想将它应用于两种不同的具体类型(Integer
和 String
).
这行不通:
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());
问题是您希望 finder
的 apply
方法是通用的。
解决方案是使用泛型方法定义您自己的功能接口。
@FunctionalInterface
interface Finder {
<T> T apply(Map<T, T> map);
}
private static String fun(Finder finder) {
// same body
}
如果这算作 "helper class" 那么我不知道该告诉你什么。你正试图将一个方形的钉子敲入一个圆孔中。 Function#apply
不是通用方法,因此您不能使用 Function
.
问题是,如果泛型签名由多个相同类型的?
组成,则以下代码无法编译。
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
,然后你想将它应用于两种不同的具体类型(Integer
和 String
).
这行不通:
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());
问题是您希望 finder
的 apply
方法是通用的。
解决方案是使用泛型方法定义您自己的功能接口。
@FunctionalInterface
interface Finder {
<T> T apply(Map<T, T> map);
}
private static String fun(Finder finder) {
// same body
}
如果这算作 "helper class" 那么我不知道该告诉你什么。你正试图将一个方形的钉子敲入一个圆孔中。 Function#apply
不是通用方法,因此您不能使用 Function
.