这似乎是一个非常愚蠢的问题,但我无法理解为什么这样使用Optional<T>编译:
import java.util.Optional;
public class Driver {
static void foo(Optional<String> x) { }
public static void main() {
foo(Optional.empty());
}
}
Run Code Online (Sandbox Code Playgroud)
Optional::empty被定义为给我一个回报Optional<T>.在里面Driver::main,表达Optional.empty()似乎会返回一个Optional<Object>,因为我没有参数化使用,Optional所以我希望它回退Object为类型参数.然后,我将传递Optional<Object>给一个函数,该函数需要一个Optional<String>参数的向下转换,这是不允许的.我希望看到类似的东西:
incompatible types: Optional<Object> cannot be converted to Optional<String>
Run Code Online (Sandbox Code Playgroud)
但是,代码编译完全正常.显然,我的思维过程不正确......但在哪里?
让我在这里的答案中澄清我正在寻找的内容......我知道什么是类型推断.我不明白它是如何发生的,以及从Java 7到Java 8的语言发生了什么变化.例如,这些代码在Java 8中编译得非常好,但在Java 7中失败了:
final class Opt<T> {
private final T value;
Opt(T x) {
value = x;
}
public static <T> Opt<T> empty() {
return new Opt<T>(null);
}
}
public class Driver {
static void bar(Opt<String> x) { }
public static void main() {
bar(Opt.empty());
}
}
Run Code Online (Sandbox Code Playgroud)
当你必须处理重载等事情时,它如何在Java 8中工作?是否有Java语言规范的特定部分讨论这种事情?
cog*_*tos 10
这是因为在Optional中定义empty()方法的方式:
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
Run Code Online (Sandbox Code Playgroud)
注意上面的方法类型参数:
public static<T> Optional<T> empty() {
^^^ method type parameter
Run Code Online (Sandbox Code Playgroud)
这意味着当调用empty()时,它会将T绑定到其调用者的上下文,在您的情况下为String.有关更多信息,请参阅Java教程中此页面中的目标类型部分:
http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
由于您的问题的这一部分尚未解决,我将尝试总结Java 7和Java 8之间的变化.
Java 7已经有类型推断,例如你可以编写
List<String> list=Collections.emptyList();
Run Code Online (Sandbox Code Playgroud)
要么
List<String> getList() {
return Collections.emptyList();
}
Run Code Online (Sandbox Code Playgroud)
但是这种类型的推理相当有限,例如什么不起作用(除了其他)是:
List<String> list=Collections.unmodifiableList(Collections.emptyList());
Run Code Online (Sandbox Code Playgroud)
要么
List<String> getList() {
return condition? new ArrayList<>(): Collections.emptyList();
}
Run Code Online (Sandbox Code Playgroud)
这两个示例现在在Java 8下工作.这个新特性称为目标类型推断,因为它现在使用目标的类型来查找适当的类型参数.除了使嵌套方法调用和条件工作,如上例中所示,它还修复了以下示例:
List<Number> numbers=Arrays.asList(1, 2, 3, 4);
Run Code Online (Sandbox Code Playgroud)
如上所述,Java 7也有类型推断,但在这个例子中,它会推断出List<Integer>传递给参数的表达式的结果类型,asList从而产生错误.
相比之下,Java 8具有目标类型推断,并将使用赋值的目标类型推断List<Number>为表达式的类型,并发现整个语句是有效的,因为您可以使用期望的Integer对象Number.
请注意Optional.empty()并Collections.emptyList()使用相同类型的Generic构造.我在我的示例中使用了后者,因为它已经存在于Java 7中.
这是因为编译器会进行类型推断。
当编译器读取到:
static void foo(Optional<String> x) { }
public static void main() {
foo(Optional.empty());
}
Run Code Online (Sandbox Code Playgroud)
Optional.<T>empty()以 aT作为参数。foo期望Optional<String>T是String.它是在引入泛型时引入的,也许它的机制在 Java 8 的javac.
请注意,这取决于编译器:ECJ(Eclipse JDT 编译器)不理解 Javac 理解的相同 java 源(但是,它们编译“相同”字节码)。
| 归档时间: |
|
| 查看次数: |
7399 次 |
| 最近记录: |