【问题标题】:Using generic parameters with static compareObject method使用带有静态 compareObject 方法的泛型参数
【发布时间】:2008-11-05 21:12:54
【问题描述】:

我想从这个通用实用程序方法(具有许多类似方法的较大类的一部分)中删除所有“未检查”警告。在紧要关头,我可以使用 @SuppressWarnings("unchecked") 但我想知道是否可以正确使用泛型来避免警告。

该方法旨在允许调用者通过传递给 compareTo 来比较两个对象,但如果对象是字符串,它会以不区分大小写的方式进行。

public static int compareObject(Comparable o1, Comparable o2)
{
    if ((o1 instanceof String) && (o2 instanceof String))
        return ((String) o1).toUpperCase().compareTo(((String) o2).toUpperCase());
    else
        return o1.compareTo(o2);
}

这是我第一次(不正确)尝试解决方案。参数工作正常,但 o1.compareTo(o2) 行有编译错误“Comparable 类型中的方法 compareTo(capture#15-of ?) 不适用于参数 (Comparable”。

public static int compareObject(Comparable<?> o1, Comparable<?> o2)
{
    if ((o1 instanceof String) && (o2 instanceof String))
        return ((String) o1).toUpperCase().compareTo(((String) o2).toUpperCase());
    else
        return o1.compareTo(o2);
}

有什么建议吗?

【问题讨论】:

  • 作为一般说明,您可能应该使用 compareToIgnoreCase 而不是将两个字符串都转换为大写。您的方法可能存在与国际化有关的细微错误(请参阅 toUpperCase 文档)。

标签: java generics


【解决方案1】:

我刚试过这个:

public static <T extends Comparable> int compareObject(T o1, T o2) {
    if ((o1 instanceof String) && (o2 instanceof String))
        return ((String) o1).toUpperCase().compareTo(((String) o2).toUpperCase());
    else
        return o1.compareTo(o2);
}

它可以编译,但在 compareTo() 调用时会发出未经检查的强制转换警告。
我尝试将其更改为

public static <T extends Comparable<T>> int compareObject(T o1, T o2) {

并且字符串检查编译失败(“不可转换类型:找到:T,必需:字符串”)。不过,我认为这一定很接近。


编辑:正如 cmets 中所指出的,这是一个 bug in javac。第二种形式确实是正确的,但目前不会编译。尽管看起来很疯狂,但这是没有警告的代码:

public static <T extends Comparable<T>> int compareObject(T o1, T o2) {
    if (((Object) o1 instanceof String) && ((Object) o2 instanceof String))
        return ((String) (Object)o1).toUpperCase().compareTo(((String) (Object)o2).toUpperCase());
    else
        return o1.compareTo(o2);
}

如您所见,唯一的区别是所有冗余转换为 Object

【讨论】:

  • 我没有得到后一个签名的错误。你用的是什么版本的 javac?
  • Java 6。我在 NetBeans 中得到了红色的波浪线,当我从命令行尝试时也遇到了同样的错误。
  • 嗯,Eclipse 不介意,但 JDK 会,版本 5 和 6。我会说这是 JDK 中的错误。
  • 也许是这样......但是让代码应该编译但不编译并不是很有用。
  • 哇...我想这是我第一次遇到 javac 错误。我将更新答案以包含此内容。谢谢,埃里克森!
【解决方案2】:

这就是您要查找的内容:

public static <T extends Comparable<T>> int compareObject(T o1, T o2) {
    if ((o1 instanceof String) && (o2 instanceof String))
        return ((String) o1).toUpperCase().compareTo(((String) o2).toUpperCase());
    else
        return o1.compareTo(o2);
}

【讨论】:

  • 当javac中相关的bug被修复时,这是要使用的签名。
  • 已确认——在 Eclipse 中工作和编译,在 JDK 中不编译。奇怪。
【解决方案3】:

我希望您知道这里的许多方法确实会改变方法的语义。使用原始方法,您可以比较不同类型的对象(如果它们允许的话),但是使用

public static <T extends Comparable<T>> int compareObject(T o1, T o2)

你不能再做这种比较了。允许这样做的变体是

    public static int compareObject2(Comparable<Object> o1, Comparable<Object> o2) {
    if (((Object) o1 instanceof String) && ((Object) o2 instanceof String))
        return ((String) (Object)o1).toUpperCase().compareTo(((String) (Object)o2).toUpperCase());
    else
        return o1.compareTo(o2);
}

(我为提到的 javac 错误插入了解决方法。)但这并不能增强类型安全或任何东西,所以在这种情况下,使用更易于理解的非泛型方法并使用 @SuppressWarnings("unchecked") 可能会更好。存在过度使用泛型这样的事情。

【讨论】:

  • 谢谢,请注意。我实际上对已回答解决方案的新语义感到满意,但看到这一点很有帮助。
【解决方案4】:

下面的呢:

  public static <T extends Comparable<T>> int compareObjects(T o1, T o2)
  {
    return o1.compareTo(o2);
  }

  public static int compareObjects(String o1, String o2)
  {
    return o1.compareToIgnoreCase(o2);
  }

缺点是当调用 compareObjects() 时使用恰好是字符串的对象,编译器会将您的调用绑定到第一个函数,并且您最终会得到区分大小写的比较。

【讨论】:

    【解决方案5】:

    您是否测试了以下内容?

    public static <T> int compareObject(Comparable<T> o1, Comparable<T> o2)
    {
        if ((o1 instanceof String) && (o2 instanceof String))
            return ((String) o1).toUpperCase().compareTo(((String) o2).toUpperCase());
        else
            return o1.compareTo(o2);
    }
    

    我认为它应该可以正常工作。

    【讨论】:

    • 我刚查了一下,没有。
    猜你喜欢
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 2021-08-13
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多