带抽象参数和继承的Java抽象方法

时间:2010-06-30 10:06:30

标签: java inheritance abstract-class instanceof

我最近遇到了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(如果它效率低下,作为我的“抽象”实现可能效率更低。

3 个答案:

答案 0 :(得分:3)

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

更新:

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

public abstract class A {
    public <T extends A> 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 extends A> T sum(T b) {
            System.out.println("B.sum(B) called");
            return null;
        }
    }
}

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

答案 1 :(得分:3)

通常可以使用访问者模式来避免

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

诀窍是,当要求对象访问访问者时,对象本身会在访问者中选择正确的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;不久之前我写了一个访问者,所以如果我在这个(几乎未经测试的)代码片段中有任何错误,请纠正我。或者更好,自己编辑帖子并改进它:)

答案 2 :(得分:0)

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