使用多种泛型类型在 Java 中实现抽象泛型方法
Posted
技术标签:
【中文标题】使用多种泛型类型在 Java 中实现抽象泛型方法【英文标题】:Implementing Abstract Generic Method in Java with multiple generics types 【发布时间】:2012-12-10 00:59:39 【问题描述】:它是关于 java 中具有两种泛型类型(一种用于返回类型,另一种用于形式参数)的泛型方法以及如何实现它。 我想我在图片中遗漏了一些东西来让它工作。
问题是这样的……
这是工作:
public enum Getter
BillItemsSize
@Override
public Integer get (Object entity)
DesiredClass ref = (DesiredClass ) entity; // "Old time" cast
// do things...
;
public abstract <T,K> T get (K entity);
这不起作用:
public enum Getter
BillItemsSize
@Override
public Integer get (DesiredClass entity) // no cast at all
// do things
;
public abstract <T,K> T get (K entity);
java 编译器这样喊我:
<anonymous datasource.db.Getter$1> is not abstract and does not override abstract method <T,K>get(K) in Getter
嗯,情况就是这样。 在此先感谢大家! 希望它在未来对其他人有所帮助!。
P.D:这不是枚举类型的问题。它发生在类层次结构中。所以不要费心去责怪枚举,我试过了,但没有用。
public abstract class SuperClass
public abstract <T,E> T pepe (E e);
public class SubClass extends SuperClass
@Override
public Integer pepe(DesiredClass e) // fails...
return null;
更新:
对于泛型参数
我们可以制定一个通用规则声明,对于“泛型参数”(其类型是泛型的),方法签名中隐式采用的类型等于该泛型的上限,可以是 Object,如果没有指定,或更具体的子类,如果使用了上限(例如 T 扩展字符串)。
对于泛型返回类型
用特定返回类型覆盖泛型方法没有问题,只要返回类型是被覆盖返回类型的子类型。首先返回类型是什么?好吧,它恰好是对象。默认情况下,编译器假定(在方法签名中)泛型类型为 Object 类型。
所以我们必须知道,任何具有通用返回类型的方法实际上都具有 Object 返回类型。 然后,如果在任何子类中该方法被覆盖并且我们改变他的返回类型声明返回另一种类型,就不会有问题。因为,除了该方法将返回另一个类的对象之外,返回的对象将不可避免地是 Object 类的子类,并且只要它是原始的子类型,覆盖具有不同返回类型的方法就没有问题。 .称为协变返回类型的技术允许我们做这样的事情。
public abstract class SuperClass
public abstract <T> T operation ();
public class SubClass extends SuperClass
@Override
public Chair operation()
//bla bla
同时在代码的另一部分...
void main ()
SubClass sb = new SubClass();
Chair chair = sb.operation ();
// the chair type can be easely replaced by super type (like Object)
Object object = sb.operation();
感谢所有帮助解决这个问题的人!
【问题讨论】:
<T,K> get (K)
在第二种情况下K === Object
没有实现。
【参考方案1】:
public abstract <T,K> T get (K entity);
是一个可以接受任何东西作为参数的方法,并且可以返回任何东西。
用
覆盖它public Integer get (DesiredClass entity)
不起作用,因为您将可以传递给方法的参数类型限制为 DesiredClass,从而违反了 Liskov 原则。
没有泛型会更容易理解。假设您在 Bar 类中有一个抽象方法:
public abstract void fillRecipient(Recipient r);
你尝试在 SubBar 中用
覆盖它public void fillRecipient(Glass glass)
如果上面的代码是合法的,下面的代码会做什么?
Bar bar = new SubBar();
bar.fillRecipient(new Mug());
【讨论】:
我明白了,“Mug”可以解释为 Glass 或 Recipient,因此这个结果是模棱两可的调用。 那么我们能否制定一个通用规则声明,对于“泛型参数”(其类型是泛型的),方法签名中隐式采用的类型等于该泛型的上限,可以是 Object , 如果没有指定,或者如果使用了上限,则使用更具体的子类(例如 T 扩展字符串)? 是的。T
等价于 T extends Object
。【参考方案2】:
为了完成 JB Nizet 的answer,当你写的时候:
<K>
隐含的意思是:
<K extends Object>
该方法必须接受任何对象。将其限制为子类上的DesiredClass
不会有效地覆盖任何内容,就像错误消息所说的那样。
被覆盖的方法必须具有完全相同的签名,不允许在参数或返回类型中出现子/超类型。
编辑:实际上正如 cmets 中所讨论的,String public foo();
有效地覆盖了Object public foo();
。
【讨论】:
但是泛型返回类型呢?用特定的返回类型覆盖泛型方法没有问题。我的猜测是因为那部分没有办法打破 Liskov 原则。不是吗?。public String foo()
不会覆盖 public Object foo()
(尝试用 @Override
注释前者,看看会发生什么)。您可以从覆盖的public Object foo()
返回String
,因为String
是a(n) Object
aahhh 所以诀窍实际上在方法内部,重新调整的对象可以是任何类型,因为方法返回类型是一个对象。因此,任何具有通用返回类型的方法实际上都具有 Object 返回类型,并且它并不关心 hack 将返回什么(只要是一个对象,这是不可避免的)。这就是所谓的协变返回类型吗?
@PabloFernandez:请尝试使用 Override,您会发现通过指定更具体的返回类型来覆盖方法是有效的。 Vitucho:你的解释是对的。
@JBNizet 绝对。我的错。我确实创建了一个示例,但由于另一个原因失败了 :( 这样做是有道理的,因为返回类型不是方法签名的一部分。以上是关于使用多种泛型类型在 Java 中实现抽象泛型方法的主要内容,如果未能解决你的问题,请参考以下文章