Java 实现包含其他泛型定义的原始接口
给定以下接口和类:Java 实现包含其他泛型定义的原始接口,java,generics,type-erasure,raw-types,Java,Generics,Type Erasure,Raw Types,给定以下接口和类: public interface Interface<T> { List<T> get(List<List<Object>> keys); } public class Cls implements Interface { @Override public List get(List<List<Object>> keys) { return Collections
public interface Interface<T> {
List<T> get(List<List<Object>> keys);
}
public class Cls implements Interface {
@Override
public List get(List<List<Object>> keys) {
return Collections.emptyList();
}
}
公共接口{
列表获取(列表键);
}
公共类Cls实现接口{
@凌驾
公共列表获取(列表键){
返回集合。emptyList();
}
}
导致编译错误:
TypeTest.java:[9,11]错误:Cls不是抽象的,并且不重写接口中的抽象方法get(List)
java:[12,20]错误:名称冲突:Cls中的get(List)和接口中的get(List)具有相同的擦除,但两者都不重写另一个
但这是可行的:
public interface Interface<T> {
List<T> get();
}
public class Cls implements Interface {
@Override
public List get() {
return Collections.emptyList();
}
}
公共接口{
List get();
}
公共类Cls实现接口{
@凌驾
公共列表get(){
返回集合。emptyList();
}
}
正如这一点:
public interface Interface<T> {
List<T> get(List<List<Object>> keys);
}
public class Cls implements Interface {
@Override
public List get(List keys) {
return Collections.emptyList();
}
}
公共接口{
列表获取(列表键);
}
公共类Cls实现接口{
@凌驾
公共列表获取(列表键){
返回集合。emptyList();
}
}
我不理解这种行为。类型擦除仅适用于类型参数
T
,不是吗?为什么遗漏T
会影响不相关的列表键
参数?我认为类测试也必须是对象泛型类型。下面是代码工作
interface Interface<T> {
List<T> get(List<List<T>> keys);
}
public class Test<Object> implements Interface<Object> {
@Override
public List<Object> get(List<List<Object>> keys) {
return Collections.emptyList();
}
}
接口{
列表获取(列表键);
}
公共类测试实现接口{
@凌驾
公共列表获取(列表键){
返回集合。emptyList();
}
}
还有下面
interface Interface<Object> {
List<Object> get(List<List<Object>> keys);
}
public class Test<Object> implements Interface<Object> {
@Override
public List<Object> get(List<List<Object>> keys) {
return Collections.emptyList();
}
}
接口{
列表获取(列表键);
}
公共类测试实现接口{
@凌驾
公共列表获取(列表键){
返回集合。emptyList();
}
}
在编译时,您试图做的事情有点棘手,参考请参见类似Hashtable的类和搜索类似KeySet的类,这可能会给您一些想法 在第一个示例中,由于原始类型发生类型擦除,因此出现了编译器错误。描述使用原始类型将产生类型擦除的情况:
为了便于与非通用遗留代码接口,可以使用参数化类型(§4.5)的擦除(§4.6)或元素类型为参数化类型的数组类型(§10.1)的擦除作为类型。这种类型称为原始类型
及
原始类型的超类(分别是超级接口)是对其任何参数化调用的超类(超级接口)的擦除
本节中的其他子句还描述了字段类型、方法的返回类型和方法的参数类型也是如何进行类型擦除的
继续,如上所述:
如果构造函数或方法的签名被删除,则构造函数或方法的类型参数(§8.4.4)和方法的返回类型(§8.4.5)也会被删除
因此,方法get
的擦除是
List get(List);
您的初始示例将无法编译,因为Cls'
sget
method、get(List)
的方法签名与原始接口的方法不匹配,并且它没有实现原始接口的get
方法
这也是第二个和第三个示例编译的原因——它们正确地覆盖了原始接口接口
顺便提一下,要在不实现原始类型的情况下重写泛型接口
接口,请在implements
子句中提供类型参数:
public interface Interface<T> {
List<T> get(List<List<Object>> keys);
}
公共接口{
列表获取(列表键);
}
实施它:
class Cls<T> implements Interface<T> {
@Override
public List<T> get(List<List<Object>> keys) {
return Collections.emptyList();
}
}
类Cls实现接口{
@凌驾
公共列表获取(列表键){
返回集合。emptyList();
}
}
或
类Cls实现接口{
@凌驾
公共列表获取(列表键){
返回集合。emptyList();
}
}
只要类型与get
中的返回类型匹配,任何引用类型都可以在implements接口中工作。子句实现接口
将与方法List get(List key)
一起使用
简而言之,原始类/接口中的所有参数化类型和泛型类型都会发生类型擦除,而不管它们是否与类/接口上声明的泛型类型参数相关。为什么不实现接口
?我使用的框架的限制。我更感兴趣的是试图理解这种奇怪的行为;我已经解决了编译错误。我猜List就是T,所以实现者应该得到的是ListT
和List
是完全分开的。这是多键查找接口的简化。
class Cls<T> implements Interface<T> {
@Override
public List<T> get(List<List<Object>> keys) {
return Collections.emptyList();
}
}
class Cls implements Interface<String> {
@Override
public List<String> get(List<List<Object>> keys) {
return Collections.emptyList();
}
}