如何在Java列表中禁止不同类的实例?

时间:2017-08-24 10:38:28

标签: java list

我们说我有方法doSomething(List<A> list),我有抽象类A和实现B的具体类CA。< / p>

所以我想告诉客户传递B个对象列表或C个对象列表,但我不想让他通过3个B对象和一个列表中的2个C对象。

一种解决方案是添加新参数&#34; type&#34;并检查所有实例是否属于同一类,但该解决方案看起来并不优雅&#34;对我来说。

如果我可以注释类似@SameConcreteClasses之类的方法或类似的东西,那么调用者可以看到我期望的内容会很棒。

2 个答案:

答案 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> {
 }