我努力为这个问题找到合适的头衔,因为我观察到的现象非常奇怪。因此,我逐字逐句解释我的问题,而是向您展示一些(希望)自我描述的代码。请考虑以下参数化类:
public class GenericOptional<T> {
public GenericOptional(T someValue) {}
public T getValue() { return null; }
public Optional<String> getOptionalString() { return Optional.empty(); }
}
我想强调的是方法Optional<String>
的返回类型getOptionalString()
不依赖于 type-parameter T
。
现在看看下面的代码,它使用 Java 8u45 在 Eclipse Luna 4.4.2 中编译:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional go = (GenericOptional) obj;
Optional os = go.getOptionalString();
}
本地变量os
的类型Optional
没有 type-parameter String
! Eclipse 编译器丢失了有关固定类型参数的信息。有谁知道为什么?
现在看第二个代码示例:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional<?> go = (GenericOptional) obj;
Optional<String> os = go.getOptionalString();
}
通过将局部变量go
声明为GenericOptional<?>
,方法getOptionalString()
的返回类型现在按预期为Optional<String>
。
愿任何人解释这种行为吗?
答案 0 :(得分:4)
它不是关于Eclipse或任何东西,而是关于原始类型。
让我们回顾一下这个片段:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional go = (GenericOptional) obj;
Optional os = go.getOptionalString();
}
在这里,您正在创建GenericOptional
的原始实例,这意味着类型参数信息将完全关闭。因此,实例化原始 GenericOptional
意味着该实例将公开方法如下:
public class GenericOptional {
public GenericOptional(Object someValue) {}
public Object getValue() { return null; }
public Optional getOptionalString() { return Optional.empty(); }
}
但是,如果我们现在审核第二个代码段
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional<?> go = (GenericOptional) obj;
Optional<String> os = go.getOptionalString();
}
我们可以看到您正在制作GenericOptional
的通用实例。即使它的类型参数是<?>
,编译器也不会关闭关于类型参数的关注,因此实例将公开参数化的getOptionalString()
方法,如下所示:
public Optional<String> getOptionalString() { return Optional.empty(); }
答案 1 :(得分:4)
您正面临raw types的行为。当您使用原始类型时,无论成员的通用签名和类的类型参数之间是否存在连接,泛型都会完全完全。
这背后的原因是原始类型是仅与前Generics代码向后兼容的功能。所以要么你有泛型,要么你没有。
如果Generic方法不依赖于类的实际类型参数,则问题很容易解决:
GenericOptional<?> go = (GenericOptional<?>) obj;
Optional<String> os = go.getOptionalString();
使用<?>
暗示“我不知道实际的类型参数,我不在乎,但我正在使用通用类型检查”。