【问题标题】:Generic type interface that accepts both types of Collection<T> and <T>接受 Collection<T> 和 <T> 两种类型的泛型类型接口
【发布时间】:2015-03-03 15:11:49
【问题描述】:

以下Interface 允许我做displayReuestResponse&lt;String&gt; 等:

public interface RequestResponse<T> 
{
    void displayRequestResponse(T output);
}

另一方面,以下Interface 允许我传入LinkedHashSetArrayList

public interface RequestResponse<T>
{
    void displayRequestResponse(Collection<T> output);
}

我只是好奇,我们甚至可以通过(调整)一个可以接受这两种类型的Interface 来使其更通用吗?或者这不可能?

【问题讨论】:

  • 第二个接口不允许传入ArrayList
  • 第一个可以接受两种类型(以及更多)...
  • @assylias 是但不是同时
  • 只是为了论证,在您的理论实现中,接受这两种情况的方法会是什么样子?
  • 我还是不明白这个问题。你想达到什么目标?

标签: java generics java-8


【解决方案1】:

使用 java 8 你可以做类似的事情

interface RequestResponse<T>     {

    default void displayRequestResponse(Collection<? extends T> output) {
        output.foreach(this::displayRequestResponse);
    }

    void displayRequestResponse(T output);
}

因此,您不必在每个具体实现中实现采用集合的重载。

【讨论】:

  • 您只是假设该集合版本只是单个元素版本的重复变体,这不太可能。如果我不想这样呢?
  • @Unheilig:这个类型安全的。
  • @zeroflag OP 正在寻求一种以相同方法处理项目和项目集合的方法。因此,我假设他们会想要这样的东西。
  • @Unheilig 这是类型安全的 - 实例化时绑定了泛型类型 T。因此,如果您创建一个 RequestResponse 您可以传递单个字符串或任何字符串集合。
  • 已编辑,以便集合重载使用有界通配符。现在对于 RequestResponse 您可以传入 List 或 List ;以前只有 List 可以工作
【解决方案2】:

重载怎么样?

interface RequestResponse<T>
{
    void displayRequestResponse(Collection<T> output);
    void displayRequestResponse(T output);
}

【讨论】:

    【解决方案3】:

    你可以有接口,有两种方法:

    public interface RequestResponse<T>
    {
        void displayRequestResponse(Collection<T> output);
    
        void displayRequestResponse(T output);
    }
    

    【讨论】:

      【解决方案4】:

      这不可能以类型安全的方式工作。

      Collection&lt;T&gt;T 是两种完全不同的类型,没有任何共同之处。像这样的接口的实现究竟会做什么?

      如果您只传递了T,它就无法循环通过Collection&lt;T&gt;,并且它不能对仅为T 定义的Collection&lt;T&gt; 执行任何操作。

      但是,您可以使用重载和默认值来实现您想要的结果,即让一个实现涵盖两种情况:

      public interface SomeInterface<T> {
      
          default void doSomething(T oneT) {
              doSomething(Arrays.asList(oneT));
          }
      
          void doSomething(Collection<T> multipleTs);
      }
      

      这样您只需提供Collection&lt;T&gt; 案例的实现,但您也可以调用单元素版本。

      当然,您也可以反过来使用 forEach,如 Tom's answer

      【讨论】:

      • 这与我的答案相比的潜在缺点是将单个参数包装在数组中的开销。另一方面,如果要完成需要参数是 Collection 的处理,那么这就是要走的路。视情况而定。
      • 所以你说有抽象的displayRequestResponse(T output); 我不能将List&lt;String&gt; 传递给具体的displayRequestResponse(List&lt;String&gt; output)
      • Arrays.asList(oneT) 是由于数组创建而不必要的开销。只需使用Collections.singleton(oneT)
      • @Holger 你仍然在那里新建一个包装器对象 - 仍然有开销
      • @Tom McIntyre:如果你想将一个对象表示为Collection,包装它是不可避免的。但是当有一个标准的解决方案只包装实例时,没有必要创建一个大小为 1 的数组,将对象存储到数组中并包装数组。
      【解决方案5】:

      你可以这样做:

      public interface RequestResponse<T> {
          void displayRequestResponse(T output);
      }
      
      public class StringReqResp implements RequestResponse<String> {
          @Override
          public void displayRequestResponse(String output) {
              // Do what you need with the String 
          }
      }
      
      public class StringListReqResp implements RequestResponse<List<String>> {
          @Override
          public void displayRequestResponse(List<String> output) {
              // Do what you need with the list of String
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-02
        • 2014-09-19
        • 2019-12-06
        • 2019-08-04
        • 2013-08-29
        • 2011-08-13
        相关资源
        最近更新 更多