【问题标题】:In generic method <T> doSth(List<T> l), check whether T implements Comparable?在泛型方法<T> doSth(List<T> l)中,检查T是否实现了Comparable?
【发布时间】:2009-10-13 16:48:48
【问题描述】:

标题基本上说明了一切:如果我有一个在 T 中通用的 java 方法,我能找到关于 T 的任何信息吗?特别是,我可以检查T是实现了某个接口还是扩展了某个类?

我想做类似的事情

public <T> List<T> doSth(List<T> l) {

  if(T extends Comparable) {
    // do one thing
  } else {
    // do another
  }

  return l;
}

有什么提示吗?

非常感谢,

约翰内斯

【问题讨论】:

    标签: java generics instanceof


    【解决方案1】:

    不清楚您是要在编译时还是在运行时执行检查。如果你只是想确保传递给方法的列表参数包含某些类型的对象,那么适当地重新定义T

    例如,要确保编译器只允许将List&lt;Comparable&gt; 传递给此方法,请将T 重新定义为:

    public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
        // Method body omitted
    }
    

    然后您可以使用方法重载(而不是 if-else 语句)来确保为 T 的任何值调用正确的代码。换句话说,替换这个:

    public <T> List<T> doSth(List<T> l) {
    
        if(T extends Comparable) {
            // do one thing
        } else {
            // do another
        }
    
        return null
    }
    

    这些:

    public <T extends Comparable<? super T>> List<T> doSth(List<T> l) {
        // do one thing
        return null;
    }
    
    public <T> List<T> doSth(List<T> l, Class<T> clazz) {
        // do another
        return null;
    }
    

    但是,您需要记住选择要调用的重载方法和泛型类型检查仅在编译时进行!例如以下代码:

    List<? extends Serializable> alist = new ArrayList<Integer>();
    doSth(alist);
    

    实际上将调用第二个 doSth 方法,因为编译时类型参数 (? extends Serializable) 没有实现 Comparable,尽管运行时类型参数 (Integer) 实现了。

    【讨论】:

      【解决方案2】:

      否 - 由于type erasure。在执行时,你根本不知道 T 的类型。

      一种选择是将类型指定为另一个参数:

      public <T> List<T> doSth(List<T> l, Class<T> clazz) {
          if (Comparable.class.isAssignableFrom(clazz)) {
              ...
          }
      }
      

      【讨论】:

      • 呃。为什么要把Class 带进来??
      • @Tom:因为它回答了问题?我知道必须提供课程很恶心,但它确实可以完成工作......
      【解决方案3】:

      是的,您可以:

      public <T> List<T> doSth(List<T> l) {
        //You could also check every element, if there is a chance only some will be comparable
        if (l.size() >0 && l.get(0) instanceof Comparable) {
          // do one thing
        } else {
          // do another
        }
      
        return l;
      }
      

      请注意,您正在检查“l”中的元素是什么类型,而不是 T - 这是关键。

      编辑:更改了代码以处理它是一个列表的事实 - 我在原来的阅读中错过了这一点。

      【讨论】:

      • 这是错误的,有两个原因。 'l' 是 List 所以它不会是 Comparable 也不是 OP 想要的。
      • @tangens - 你是对的,我已经更正了列表问题的解决方案。抱歉错过了 - 显然我的大脑今天正在度假
      • @ChssPly76 我试图根据他们的代码推断他们想要什么,我对其进行了编辑以处理我错过的集合隐喻。
      • @aperkins - 你的更新会更好,但它仍然不能处理集合为空的情况(并且“不处理”我的意思是路由控制到“做另一个”这是不是OP暗示他想要的)。这里的底线是你不能作弊类型擦除。否决票不是我的,也许他们会在看到您的更新后将其删除。
      • @ChssPly76 我认为不是。我只是向他们展示了另一种方法来尝试确定列表中的类型而不传递 T 类。
      【解决方案4】:

      你应该在(甚至之前!:)编译时就知道 T 是否扩展了 Comparable,那么为什么不创建两个方法呢?

      public <T extends Comparable<T>> List<T> doSthComp(List<T> l) {
        // do one thing
        return l;
      }
      
      public <T> List<T> doSth(List<T> l) {
        // do another
        return l;
      }
      

      【讨论】:

      • 你可以对那里的界限更加慷慨。
      • 当然,如果您从另一个泛型类型调用它,您可能在编译时知道这一点...此时您仍然需要适当的 @ 987654322@ 对象,我的解决方案也可以工作。我讨厌类型擦除...
      【解决方案5】:

      你可以做一个

      public <T extends Comparable<T>> List<T> doSth(List<T> l)
      

      这将允许您在 'l' 中的项目上使用 Comparable 接口

      【讨论】:

        【解决方案6】:

        对于编译时检查,Don 已经给出了答案。对于运行时,只有当您还传递一个表示 T 的显式对象时才有可能,例如:
        static <T> List<T> doSth(List<T> l, Class<T> tClass) 让 tClass 对象代表 T 的真实类,您可以检查它是否已通过反射实现了可比性。但在我看来,编译时检查要好得多。

        【讨论】:

          猜你喜欢
          • 2022-12-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-18
          • 2011-10-09
          • 1970-01-01
          • 2013-10-06
          • 1970-01-01
          相关资源
          最近更新 更多