此答案基于Brian Goetz 于 2014 年 12 月撰写的这篇论文。这是我能找到的关于该主题的最新文章;但是请注意,该论文是“非正式草图”,因此对于您的问题还没有确定性。
首先, aList<int>
不会是List<Integer>
( Subtyping ) 的子类型:
最初,它可能Box<int>
是 raw 的子类型似乎也是明智的Box
。但是,考虑到我们的翻译策略,Box
该类不能是任何类表示的超类Box<int>
,因为 thenBox<int>
将具有t
type的字段Object
,而t
应该是 type int
。所以Box<int>
不能是 raw 的子类型Box
。(出于同样的原因,Box<int>
不能是 的子类型Box<Integer>
。)
...
由于泛型是不变的,因此它List<int>
不是List<Integer>
. 这里有点令人惊讶的是,一个专门的类型不能与它的原始类型互操作。然而,这并不是一个不合理的限制;不仅不鼓励使用原始类型(仅出于支持从非泛型代码到泛型代码的逐步迁移的目的而引入),而且仍然可以使用泛型方法编写完全泛型的代码——参见“泛型方法”。
本文还列出了“迁移挑战”,参考原语重载(问题是你的问题)就是其中之一:
一些今天有效的重载在专业化下会成为问题。例如,如果专门使用这些方法会出现问题T=int
:
public void remove(int position);
public void remove(T element);
这样的重载在专业化方面(生成什么方法)和重载选择方面(调用哪个方法)都是有问题的。
建议的解决方案称为“剥离”技术:
考虑类 List 类中的重载对:
interface ListLike<T> {
public void remove(int position);
public void remove(T element);
}
will的现有使用ListLike
都涉及引用实例化,因为这些是当前在预专业化世界中允许的唯一实例化。请注意,虽然兼容性要求引用实例化具有这两种方法,但它不需要非引用实例化(因为目前不存在。)
剥离背后的直觉是观察到,虽然我们习惯于将现有ListLike
类型视为泛型类型,但它实际上可能是跨所有实例化的泛型类型和仅跨引用泛型的类型的联合实例。
如果我们在后专业化世界中从头开始编写这个类,我们可能会这样写:
interface ListLike<any T> {
void removeByIndex(int position);
void removeByValue(T element);
}
但是,现在这样的更改既不兼容源代码,也不兼容二进制文件。但是,剥离允许我们将这些方法添加到泛型层,并在特定于引用的层中实现它们,而不需要它们在特化中,从而恢复兼容性:
interface ListLike<any T> {
// New methods added to the generic layer
void removeByValue(T element);
void removeByIndex(int pos);
layer<ref T> {
// Abstract methods that exist only in the ref layer
void remove(int pos);
void remove(T element);
// Default implementations of the new generic methods
default void removeByIndex(int pos) { remove(pos); }
default void removeByValue(T t) { remove(t); }
}
}
现在,引用实例化具有remove(T)
, 和remove(int)
(以及新方法removeByIndex
and ),确保兼容性,并且特化具有无问题的andremoveByValue
重载。的现有实现将继续编译,因为新方法具有引用专业化的默认实现(它只是桥接到现有的删除方法)。对于值实例化,and被视为抽象且必须提供,但 remove 根本不存在。removeByValue(T)
removeByIndex(int)
ListLike
removeByIndex
removeByValue
该技术还支持“按部分实现”技术;可以在泛型层中声明方法抽象,并在值层和参考层中提供具体实现。如果我们允许 的层T=int
,它也将启用“专业化专业化”技术。
使用这种技术,将保持向后兼容性并使用新removeByValue
方法removeByIndex
。