我们说我有方法doSomething(List<A> list)
,我有抽象类A
和实现B
的具体类C
和A
。< / p>
所以我想告诉客户传递B
个对象列表或C
个对象列表,但我不想让他通过3个B
对象和一个列表中的2个C
对象。
一种解决方案是添加新参数&#34; type&#34;并检查所有实例是否属于同一类,但该解决方案看起来并不优雅&#34;对我来说。
如果我可以注释类似@SameConcreteClasses
之类的方法或类似的东西,那么调用者可以看到我期望的内容会很棒。
答案 0 :(得分:2)
这不是你应该如何在Java中使用继承。
您的列表会收集类类型A的项目。任何迭代该列表的对象都将确保类型A的所有方法都可用,并使用A中定义的类型值进行响应。
如果您需要B类或C类中提供的方法,那么我建议您添加一个支持管道中所需方法的接口,将其添加到您的类中,然后可以在管道中进一步访问使用它的任何方法,无论添加到List<MyInterface>
您希望开发人员知道您期望/需要哪些方法,这基本上也是界面的教科书定义。
这是对未来开发人员的暗示:&#34;我需要定义方法a,b,c和z来返回这样的类型。只要这些方法可供我使用,我就不在乎你是如何构建它的,或者如果你嘲笑它。&#34;
并且您可以放心,您的方法调用不会抛出错误,您可能只会偶尔返回null。
首先考虑您的管道,以及他们需要哪些方法 然后为这些方法编写一个接口 然后将该接口添加到适用的类中 然后使列表只接受具有该接口的项目。
class A {
protected int count = 1;
public int getCount() {
return this.count;
}
}
class B extends A{
private String name = "B";
public String getName(){
return this.name;
}
}
class C {
private String name = "C";
public int getCount() {
return 20;
}
public String getName(){
return this.name;
}
}
让我们说在收集了所有类的管道的最后我们有一个方法:
public void outputFull(List<????> output) {
for(???? item : output) {
if(item.getCount() > 1) {
System.out.println(item.getName() + " has " + item.getCount() + " items");
}
}
}
我用???标记了类型因为我们还不知道我们需要什么&#39;
因此,从我们通过管道的最终方法中我们知道我们需要具有int getCount()
和String getName()
方法的对象。
我们可以为此编写一个界面:
public interface INamedCountable {
public int getCount();
public String getName();
}
通过该界面,我们可以将我们希望的对象转换为该接口类型
class A {
protected int count = 1;
public int getCount() {
return this.count;
}
}
class B extends A implements INamedCountable {
private String name = "B";
public String getName(){
return this.name;
}
}
class C implements INamedCountable {
private String name = "C";
public int getCount() {
return 20;
}
public String getName(){
return this.name;
}
}
对于我们的管道,我们可以使用:
public void outputFull(List<INamedCountable> output) {
for(INamedCountable item : output) {
if(item.getCount() > 1) {
System.out.println(item.getName() + " has " + item.getCount() + " items");
}
}
}
public void runPipe() {
List<INamedCountable> pipeline = new ArrayList<INamedCountable>();
pipeline.add(new B());
pipeline.add(new C());
outputFull(pipeline);
}
答案 1 :(得分:0)
您可以添加其他参数Class<A>
并使用Generic methods来同步两个参数的类型
private <T extends A> void doSomething(List<T> list, Class<T> clazz) {
}
doSomething(new ArrayList<B>(), B.class);
doSomething(new ArrayList<C>(), C.class);
doSomething(new ArrayList<B>(), C.class); <-- compile error here
doSomething(new ArrayList<A>(), B.class);<-- compile error here
它将强制客户端决定他想要在方法中传递的实际类,但仍然可以通过doSomething(new ArrayList<A>(), A.class);
传递
将doSomething
提取到接口(抽象类)并为其创建两个实现的另一种解决方案:
private abstract class ExecutorForA<T extends A> {
private void doSomething(List<T> list) {
}
}
private class ExecutorForB extends ExecutorForA<B> {
}
private class ExecutorForC extends ExecutorForA<C> {
}