簡體   English   中英

如何在Java列表中禁止不同類的實例?

[英]How to forbid instances of different classes in Java list?

假設我有方法doSomething(List<A> list) ,我有抽象類A和實現A具體類BC

所以我想告訴客戶端傳遞B對象列表或C對象列表,但我不想讓他在一個列表中傳遞3個B對象和2個C對象。

一種解決方案是添加新參數“type”並檢查所有實例是否屬於同一類,但該解決方案對我來說似乎並不“優雅”。

如果我可以注釋像@SameConcreteClasses類的方法或類似的東西,那么調用者可以看到我期望的東西會很棒。

這不是你應該如何在Java中使用繼承。

您的列表將收集類類型A的項。任何迭代該列表的對象都將確保類類型A的所有方法都可用,並使用A中定義的類型值進行響應。

如果您需要B類或C類中提供的方法,那么我建議您添加一個支持管道中所需方法的接口,將其添加到類中,然后使用它的任何方法都可以在管道中進一步訪問,無論是添加到List<MyInterface>的類的類型

您希望開發人員知道您期望/需要的方法,這也基本上是接口的教科書定義。
這是你對未來開發人員的暗示: “我需要定義方法a,b,c和z來返回這樣的類型。我不關心你如何構建它,或者如果你嘲笑它,只要這些方法我可以使用。“
並且您可以放心,您的方法調用不會拋出錯誤,您可能只會偶爾返回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");
          }
     }
}

我用???標記了類型 因為我們還不知道我們需要什么

因此,從傳遞給管道的最終方法中我們知道我們需要具有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);
}

您可以添加其他參數Class<A>並使用Generic方法來同步兩個參數的類型

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(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> {
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM