带抽象参数和inheritance的Java抽象方法

我最近遇到了一个API和一个实现的问题,其中出现了以下类型的代码:

API是一个抽象类:

public abstract class A { public A sum(A a) { System.out.println("A.sum(A) called"); return null; } } 

实现是一个简单的类:

 public class B extends A { public B sum(B b) { System.out.println("B.sum(B) called"); return null; } } 

说到使用它我写道:

 public class Main { public static void main(String args[]) { B b = new B(); A basa = new B(); b.sum(b); basa.sum(b); basa.sum(basa); } } 

结果如下:

 % java Main B.sum(B) called A.sum(A) called A.sum(A) called 

我知道B的总和不会覆盖A的总和,因为它的签名是不同的,但是我想为有效类型B的对象提供有效的总和实现。我认为这样的设计是非常经典的,现在我想如何应该设计我的API和实现,以便它有效。

当然,我可以在类中提供sum(A a)并在调用sum(B)或super之前检查b是否是instanceOf B,但我认为出于效率原因而避免使用instanceOf(如果效率低,它作为我的“抽象”实现可能效率更低。

通常可以通过使用访问者模式来避免instanceof 。 根据您的需要,它可能是也可能不是过度杀伤力。 它很灵活但很冗长。 在下面的示例中,我从A删除了abstract ,以说明它如何与不同类型一起使用。

诀窍在于,当要求对象访问访问者时,对象本身会在访问者中选择正确的accept方法。 “instanceof”-check通过多态解决。 (我怀疑它比instanceof更有效。)

 interface Visitor { public A accept(A a); public B accept(B b); } class A { public A sum(A a) { System.out.println("A.sum(A) called"); return null; } public A visit(Visitor sv) { return sv.accept(this); } } class B extends A { public B sum(B b) { System.out.println("B.sum(B) called"); return null; } public B visit(Visitor sv) { return sv.accept(this); } } public class Test { public static void main(String[] args) { A a = new A(); B b = new B(); A basa = new B(); a.visit(new SumVisitor(b)); // a.sum(b); b.visit(new SumVisitor(b)); // b.sum(b); basa.visit(new SumVisitor(b)); // basa.sum(b); basa.visit(new SumVisitor(basa)); // basa.sum(basa); } static class SumVisitor implements Visitor { A arg; SumVisitor(A arg) { this.arg = arg; } public A accept(A a) { return a.sum(arg); } public B accept(B b) { return b.sum(arg); } } } 

输出:

 A.sum(A) called B.sum(B) called B.sum(B) called B.sum(B) called 

Disclamer; 不久前我写了一个访问者,所以如果我在这个(几乎未经测试的)代码片段中有任何错误,请纠正我。 或者更好,自己编辑post并改进它:)

由于B实例可以使用myA.sum(myB)A实例相加,因此您应该能够更改Bsum定义,以便它覆盖,除非当然sum是占位符并且不应该是交换。

更新:

如果这还不够,你可以开始使用generics。 我的意思是粗略的传递:

 public abstract class A { public  T sum(T a) { System.out.println("A.sum(A) called"); return null; } public static void main(String args[]) { B b = new B(); b.sum(b); A basa = new B(); basa.sum(b); basa.sum(basa); } public static class B extends A { @Override public  T sum(T b) { System.out.println("B.sum(B) called"); return null; } } } 

@aioobe是正确的,普遍接受的解决方法是使用访客模式。 我提供这些不太完整但不那么冗长的替代方案。

那么,是什么让你认为instanceof很慢? 它在JDK中的几个地方使用,他们希望为抽象类或接口的某些众所周知的实现提供“快速路径”。 通常的建议适用于此:“测试,不要猜测。”