如何强制子类作为参数(或禁止父类作为参数)

时间:2018-04-05 00:28:10

标签: java

TL; DR有没有办法强制方法接收子类而不是父类?

说我有一个像:

这样的界面
interface MyInterface<T extends A>{
    process(A a)
}

和班级

abstract class A<T extends A>{
    MyInteface<T>[] processors
}

两个子类B和C如:

class B extends A<B>{}
class C extends A<C>{}

我想这样做,以便MyInterface的实现可以做类似的事情:

class MyImplementation implements MyInterface<B>, MyInterface<C>{
    process(B)
    process(C)
} 

我认为这是不可能的,因为如果将超类A传递给MyImplementation,编译器将无法告诉您该怎么做。

是否可以强制MyImplementation只接收子类?如果没有,你会如何处理这个问题?

1 个答案:

答案 0 :(得分:0)

由于Java中的type erasure,这是不可能的:在运行时,与泛型相关的类型信息不再可用。例如:

List<Number> numbers = new ArrayList<>();
List<String> strings = new ArrayList<>();

// At runtime, these types actually look like this:
List numbers = new ArrayList();
List strings = new ArrayList();

因此,单个类不能使用不同的泛型类型参数多次实现相同的通用接口。在编译期间,class MyImplementation implements MyInterface<B>, MyInterface<C> { /* ... */ }将失败。这样做会导致以下错误:

  

接口MyInterface不能多次实现   不同的论点:MyInterface<C>和   MyInterface<B>

删除类型后,此类等于class MyImplementation implements MyInterface, MyInterface { /* ... */ },这在Java中显然是不允许的。

<强>替代

好像您正在寻找要更改的调用的功能,具体取决于使用哪个类来处理元素(MyInterface<B>MyInterface<C>等)以及哪个元素是已处理(ABC等)。这称为double-dispatch,与Visitor Pattern密切相关。在您的问题的上下文中,您可以执行以下操作:

public interface Element {
    public void accept(Processor processor);
}

public class A implements Element {

    @Override
    public void accept(Processor processor) {
        processor.process(this);
    }
}

public class B implements Element {

    @Override
    public void accept(Processor processor) {
        processor.process(this);
    }
}

public interface Processor {
    public void process(A a);
    public void process(B b);
}

public class RedProcessor implements Processor {

    @Override
    public void process(A a) {
        System.out.println("Red processor got an A");
    }

    @Override
    public void process(B b) {
        System.out.println("Blue processor got an A");
    }

}

public class BlueProcessor implements Processor {

    @Override
    public void process(A a) {
        System.out.println("Blue processor got an A");
    }

    @Override
    public void process(B b) {
        System.out.println("Blue processor got an A");
    }

}

可以使用以下方法测试此代码:

Processor processor = new RedProcessor();
A a = new A();
processor.process(a);

改变Processor实施(例如RedProcessorBlueProcessor)和Element实施(例如AB)会导致不同的输出。由于结果取决于ProcessorElement,因此此技术称为 double -dispatch。