看看下面例子中泛型类型的类型推断,我说不出为什么methodAutoTypeInference
工作得很好,但是methodnotcompileable
(几乎相同)无法编译,为了管理它,编译器需要额外的技巧,比如methodWorkaroundTypeHint
或methodWorkaroundTypeCast
。
导致编译器不确定表达式类型和方法结果类型是否兼容的问题是什么?
Stream<CharSequence> methodAutoTypeInference() {
return Stream.of("a");
}
Stream<CharSequence> methodNotCompilable() {
return Stream.of("a").distinct();
// incompatible types: java.util.stream.Stream<java.lang.String>
// cannot be converted to java.util.stream.Stream<java.lang.CharSequence>
}
Stream<CharSequence> methodWorkaroundTypeHint() {
return Stream.<CharSequence>of("a").distinct();
}
Stream<CharSequence> methodWorkaroundTypeCast() {
return Stream.of((CharSequence) "a").distinct();
}
您会发现这种行为相当多。尤其是当将比较器
链接为编译器时,根本无法推断链中的适当类型。下面是您的解决方案。
Stream<CharSequence> methodWorkaroundTypeHint() {
return Stream.<CharSequence>of("a").distinct();
}
被称为类型见证
,是处理这些问题的典型解决方案。查看此答案以了解更多详细信息。
这是编译器的功能。当你写流时。属于(“a”)
With return语句和method of()编译器的泛型类型从方法参数“a”(Stream)获取类型
当您编写
返回流时。属于(“a”)
编译器从返回类型(
流)获取类型
换句话说,您不为()的方法设置泛型类型,当您没有另一个流的方法时,编译器从方法的返回类型获取泛型类型,如果您有其他流的方法,编译器从变量的类型获取类型。
JDK Developers自己给出的答案也涵盖了同样的领域。请注意,斯图尔特·马克斯说:“编译器可能会得到增强,以便在未来的版本中涵盖这种情况”。尽管这种情况与lambdas
有关,但这与您的情况没有太大不同。这只是编译器(目前)的工作方式。我们“被卡住了”。
您可以在编译器如何看待返回Stream.of("a")的分辨率下进行查找。
javac --debug=verboseResolution=all
它在一个未记录的标志中。如果你用这个标志编译,你会看到一些大的输出:
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: Object()
DeleteMe.java:60: Note: resolving method of in type Stream to candidate 1
return Stream.of("a").distinct();
^
phase: BASIC
with actuals: String
with type-args: no arguments
candidates:
#0 not applicable method found: <T#1>of(T#1...)
(cannot infer type-variable(s) T#1
(argument mismatch; String cannot be converted to T#1[]))
#1 applicable method found: <T#2>of(T#2)
(partially instantiated to: (String)Stream<String>)
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>of(T#1...)
T#2 extends Object declared in method <T#2>of(T#2)
DeleteMe.java:60: Note: Deferred instantiation of method <T>of(T)
return Stream.of("a").distinct();
^
instantiated signature: (String)Stream<String>
target-type: <none>
where T is a type-variable:
T extends Object declared in method <T>of(T)
DeleteMe.java:60: Note: resolving method distinct in type Stream to candidate 0
return Stream.of("a").distinct();
^
phase: BASIC
with actuals: no arguments
with type-args: no arguments
candidates:
#0 applicable method found: distinct()
where T is a type-variable:
T extends Object declared in interface Stream
DeleteMe.java:60: error: incompatible types: Stream<String> cannot be converted to Stream<CharSequence>
return Stream.of("a").distinct();
^
1 error
我猜最重要的部分是:
(部分实例化为:(String)Stream
您可以看到,
T
类型的解析是在方法调用的基础上完成的;而不是整个通话链。如果会的话,顺便说一句,这将使编译器的工作变得非常复杂。对于这样一个简单的链,事情可能看起来很琐碎,但当有很多的时候,事情变得越来越棘手和复杂。尤其是,当你发现不可表示的类型时,这将使问题更加复杂。
问题内容: 我正在使用Java 的本地实现,该实现具有如下方法: 这两种方法可以编译并正常工作: 此方法无法编译: 错误: (我已经修剪了包限定符,以使错误更易读) 我可以通过指定类型进行编译: 但是为什么我需要呢?以及如何避免此代码混乱? 问题答案: 此代码应该起作用。 它在最新的JDK 1.8.0_121上编译。 无法在JDK 1.8.0-51上编译。 这意味着它在此版本的JDK中很可能是一个
我使用的是Java中的<code>或者</code>的本地实现,它有如下方法: 这两种方法可以编译并正常工作: 此方法不编译: 错误: (我去掉了包限定符,使错误更加易读) 我可以通过指定类型来编译它: 但我为什么需要这样做?我如何避免这种代码混乱?
问题内容: 如果在Java中创建泛型类(该类具有泛型类型参数),则可以使用泛型方法(该方法带有泛型类型参数)吗? 考虑以下示例: 正如您对通用方法所期望的那样,我可以使用任何对象调用的实例: 但是,如果我尝试使用 不 指定泛型类型的实例,则无论传入什么,我都会调用返回, 奇怪的是,如果返回类型是通用类,它将编译(例如(实际上,这可以解释-参见下面的答案)): 此外,如果输入通用类,即使仅使用通配符
如果在Java中创建泛型类(该类具有泛型类型参数),是否可以使用泛型方法(该方法采用泛型类型参数)? 考虑下面的例子: 正如您所期望的那样,对于任何对象,的实例,我都可以调用: 但是,如果我试图使用的实例而不指定泛型类型,那么调用将返回一个
此代码在Java 8中编译,但在Java 7中编译失败: 它不能推断从映射返回的映射的具体类型。空(): 如果将调用更改为f(Map),则会编译。 但是如果您将调用更改为f(Map.empty())。放(1,“A”)。put(2,“B”)) ,它无法在Java 7和8上再次编译。为什么?
本文向大家介绍Java8中对泛型目标类型推断方法的改进,包括了Java8中对泛型目标类型推断方法的改进的使用技巧和注意事项,需要的朋友参考一下 一、简单理解泛型 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。通俗点将就是“类型的变量”。这种类型变量可以用在类、接口和方法的创建中。 理解Java泛型最简单的方法是把它看成一种便捷语法,能节省你