public static void main(String[] args) {
Map<String, Map<Long, List<String>>> map = getHashMap();
}
static <K,V> Map<K,V> getHashMap()
{
return new HashMap<K, V>();
}
我在google guava(作为工厂方法)中看到了类似的代码,用于制作Hashmap的实例而不提及泛型类型。我不明白如何通过上述程序推断泛型。我的意思是函数getHashMap如何了解地图的类型,因为我没有将任何类型的信息传递给函数。
答案 0 :(得分:6)
getHashMap
函数不必推断类型。在Java语言规范中,javac需要javac来推断类型是否一致(15.12.2.7 Inferring Type Arguments Based on Actual Arguments)。
我认为目前的计划(仍然)是JDK7支持菱形运算符,所以这类事情也适用于new
,尽管有一些明显无意义的语法。
Map<String, Map<Long, List<String>>> map = new HashMap<>();
^^diamond
答案 1 :(得分:1)
在字节码级别,该方法将有一个描述符,只是说,有一个名为getHashMap的方法,它不带参数并返回一个Map(没有泛型)。
然后,当编译器正在分析行Map<String, Map<Long, List<String>>> map = getHashMap();
时,它会说,好吧,我需要一个声明类型为Map<String, Map<Long, List<String>>>
的变量,但要实际获取我需要的实例叫一个方法。此时,编译器的工作是检查方法的返回类型是否与您为其分配结果的变量的声明类型相匹配。因此,它会检查String
是否与K
匹配,如果Map<Long, List<String>>
与V匹配,那么它会认为赋值是类型安全的,并生成基本上使用Map的字节码(没有泛型)变量。
如果您将方法声明为:
static <K extends Number,V> Map<K,V> getHashMap()
{
return new HashMap<K, V>();
}
在分析赋值时,编译器会看到String
与K extends Number
不匹配,会抛出编译错误,并且不会为该赋值创建字节码。
答案 2 :(得分:1)
class XX
static <T> T foo(){ return null; }
String s = XX.foo();
Integer i = XX.foo();
Java推断第一种情况下T是String,第二种情况下是Integer。
“推断”是什么意思?这意味着Java猜测在两个语句中,程序员最喜欢在第一种情况下需要T == String,对于第二种情况T == Integer,作为一个好人,Java将这些猜测视为事实,程序员不会必须手动指定Ts
String s = XX.<String> foo();
Integer i = XX.<Integer>foo();
但实际上,Java 指示必须像这样确定返回类型T
。
我发现这件事非常可疑,不确定设计背后的原因是什么。也许,当(if)Java添加可再生类型(即运行时可用T
的真实类)时,设计更有意义:
class XX
static <T> T foo(){ return new T(); }
String s = XX.foo();
Integer i = XX.foo();
我仍然不喜欢方法类型与上下文相关的事实。