为什么 Eclipse Compiler 会丢失固定类型参数?
Why does Eclipse Compiler lose fixed type parameter?
我为这个问题找了一个合适的标题,因为我观察到的现象很奇怪。因此,我跳过从字面上解释我的问题,而是向您展示一些(希望如此)self-describing 代码。考虑以下参数化 class:
public class GenericOptional<T> {
public GenericOptional(T someValue) {}
public T getValue() { return null; }
public Optional<String> getOptionalString() { return Optional.empty(); }
}
我想强调的是方法getOptionalString()
的return类型Optional<String>
不依赖于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 编译器丢失了有关固定 type-parameter 的信息。有谁知道为什么?
现在看第二个代码示例:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional<?> go = (GenericOptional) obj;
Optional<String> os = go.getOptionalString();
}
通过将局部变量 go
声明为 GenericOptional<?>
,方法 getOptionalString()
的 return 类型现在是预期的 Optional<String>
。
谁能解释一下这种行为?
这不是关于 Eclipse 或任何东西,而是关于原始类型。
让我们回顾一下这个片段:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional go = (GenericOptional) obj;
Optional os = go.getOptionalString();
}
在这里,您正在创建 GenericOptional
的 raw 实例,这意味着类型参数信息将被完全关闭。因此,实例化一个 raw 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(); }
您正面临 raw types 的行为。当您使用原始类型时,无论成员的泛型签名与 class 的类型参数之间是否存在联系,泛型都会被有效地 完全 关闭.
这背后的原因是 原始类型 是一种仅向后兼容预泛型代码的功能。所以要么你有泛型,要么没有。
如果Generic方法不依赖class的实际类型参数,问题很容易解决:
GenericOptional<?> go = (GenericOptional<?>) obj;
Optional<String> os = go.getOptionalString();
使用 <?>
意味着“我不知道实际的类型参数,我不在乎,但我正在使用通用类型检查”。
我为这个问题找了一个合适的标题,因为我观察到的现象很奇怪。因此,我跳过从字面上解释我的问题,而是向您展示一些(希望如此)self-describing 代码。考虑以下参数化 class:
public class GenericOptional<T> {
public GenericOptional(T someValue) {}
public T getValue() { return null; }
public Optional<String> getOptionalString() { return Optional.empty(); }
}
我想强调的是方法getOptionalString()
的return类型Optional<String>
不依赖于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 编译器丢失了有关固定 type-parameter 的信息。有谁知道为什么?
现在看第二个代码示例:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional<?> go = (GenericOptional) obj;
Optional<String> os = go.getOptionalString();
}
通过将局部变量 go
声明为 GenericOptional<?>
,方法 getOptionalString()
的 return 类型现在是预期的 Optional<String>
。
谁能解释一下这种行为?
这不是关于 Eclipse 或任何东西,而是关于原始类型。
让我们回顾一下这个片段:
public static void main(String[] args) {
Object obj = new GenericOptional<>(Boolean.TRUE);
GenericOptional go = (GenericOptional) obj;
Optional os = go.getOptionalString();
}
在这里,您正在创建 GenericOptional
的 raw 实例,这意味着类型参数信息将被完全关闭。因此,实例化一个 raw 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(); }
您正面临 raw types 的行为。当您使用原始类型时,无论成员的泛型签名与 class 的类型参数之间是否存在联系,泛型都会被有效地 完全 关闭.
这背后的原因是 原始类型 是一种仅向后兼容预泛型代码的功能。所以要么你有泛型,要么没有。
如果Generic方法不依赖class的实际类型参数,问题很容易解决:
GenericOptional<?> go = (GenericOptional<?>) obj;
Optional<String> os = go.getOptionalString();
使用 <?>
意味着“我不知道实际的类型参数,我不在乎,但我正在使用通用类型检查”。