【问题标题】:Comparing elements in a generic list比较通用列表中的元素
【发布时间】:2012-10-12 00:12:51
【问题描述】:

今年早些时候,我为我的 java 类编写了一个链表实现。这是一个名为 LList 的通用类。我们现在必须写出一个实验室的归并排序算法。我决定重用之前创建的通用列表,而不是创建一个采用 Ints 的新 List 实现。

问题是如何比较两个通用对象? java不会让我做类似的事情

if(first.headNode.data > second.headNode.data)

所以,我的问题是,他们是否可以实现某种适用于任何类型数据的比较功能?我尝试了以下方法:

        String one, two;
        one = first.headNode.data.toString();
        two = second.headNode.data.toString();
        if(first.headNode.data.compareTo(second.headNode.data) < 0) {
            result.add(first.headNode.data);
            // remove head node. remove() takes care of list size.
            first.remove(1);
        } else {
            // If compareTo returns 0 or higher, second.headNode is lower or
            // equal to first.headNode. So it's safe to update the result
            // list
            result.add(second.headNode.data);
            second.remove(1);
        }

这甚至无法正常工作。我用数字 6 和 12 进行了测试,上面将 12 添加到结果列表中。

相关资料:

 private LList<T> mergeSort(LList<T> list) {
    LList<T> first = new LList();
    LList<T> second = new LList();
    if (list.length() == 1) {
        return list;
    }

    int middle = list.length() / 2;
    second.headNode = list.getNodeAt(middle + 1);
    second.length = list.length() - (middle);
    // Set first half to full list, then remove the "second" half.
    first.headNode = list.headNode;
    first.length = middle;
    first.getNodeAt(middle).next = null;

    // Get the splitted halves.
    first = mergeSort(first);
    second = mergeSort(second);
    return merge(first, second);
}

private LList<T> merge(LList<T> first, LList<T> second) {
    LList<T> result = new LList();

    while((first.length > 0) && (second.length > 0)) {
        // Ok, lets force toString to compare stuff since generics are a pain.
        String one, two;
        one = first.headNode.data.toString();
        two = second.headNode.data.toString();
        if(one.compareTo(two)) < 0) {
            result.add(first.headNode.data);
            // remove head node. remove() takes care of list size.
            first.remove(1);
        } else {
            // If compareTo returns 0 or higher, second.headNode is lower or
            // equal to first.headNode. So it's safe to update the result
            // list
            result.add(second.headNode.data);
            second.remove(1);
        }
    }
    return result;
}

注意:整个 LList 类可以在 [这里](http://rapidshare.com/files/219112739/LList.java.html MD5: BDA8217D0756CC171032FDBDE1539478)

【问题讨论】:

  • 如果您想“作弊”,请查看 Java 源代码中的 Collections.sort() 之类的内容。安装 JDK 时,应该有一个安装源的选项。然后在你的安装目录下会有一个 src.jar 文件。 .jar 文件可以重命名为 .zip 并在 WinZip 中打开。

标签: java generics


【解决方案1】:

请注意,Comparable 也是一个泛型类型,由它可比较的类型参数化。上面声明 mergeSort 函数的最通用、类型安全的方法是:

private <T extends Comparable<? super T>> LList<T> mergeSort(LList<T> list) { }

这强制类型 T 的 compareTo 方法可以接受类型 T 的参数。(理论上,一个类型可以实现 Comparable,但不能与自身进行比较,例如 SomeClass implements Comparable&lt;CompletelyDifferentClass&gt;,因此对Comparable 的类型参数。然而,在实践中,任何设计良好的 Comparable 类都应该至少与自身具有可比性。)

我们需要&lt;T extends Comparable&lt;? super T&gt;&gt; 而不仅仅是&lt;T extends Comparable&lt;T&gt;&gt;,因为如果类型T 的compareTo 方法接受比T 更通用的类型是可以的,因为它仍然能够接受类型T 的参数。这个很重要,因为如果您有一个实现Comparable&lt;A&gt; 的类A;然后你有一个扩展A的子类B,B不能实现Comparable&lt;B&gt;,因为B已经实现了Comparable&lt;A&gt;,继承自A,一个类不能实现一个接口两次。因此,如果我们要求上面的&lt;T extends Comparable&lt;T&gt;&gt;,B 将无法满足它,我们将无法对LList&lt;B&gt; 对象进行排序。

【讨论】:

  • 我该如何写 return merge(first, second);如果第一个和第二个是 LList? LList.java:207:mattrlab2.LList 中的 merge(mattrlab2.LList,mattrlab2.LList) 不能应用于 (mattrlab2.LList,mattrlab2.LList ) 这就是我最终的结果,不确定问题是什么......
  • 忽略上面的评论,我才意识到我总是会比较苹果和苹果,因为 mergeSort 在 LList 类中。
  • 只是那种让初学者“去他妈的,我主修哲学”的代码。 :)(并不是说它是糟糕的代码,但是如果你没有经常使用 Java 的泛型类型语法会变得非常丑陋)
【解决方案2】:

查看ComparatorComparable 接口。

您的排序方法应该采用Comparator 或者您应该指定 以便可以使用Comparable 接口。

public void sort(Comparable<T> comparator) {
    sort(SortType.MERGE, comparator);
}
....
private LList<T> merge(LList<T> first, LList<T> second) {
    ...
        if(comparator.compare(first.headNode.data, second.headNode.data) < 0) {
    ...
}

【讨论】:

    【解决方案3】:

    好吧,正如您所发现的,您遇到了问题。关于列表中的对象,您所知道的只是它们是 Object 或其子类之一的实例。您不能真正对对象进行排序。您现在有几个选择:

    你有一个选择是对完全没有意义的东西进行排序,比如对象的 hashCode。实际上,您可以使用 hashCode 实现一个完全有效的归并排序,但这在很大程度上是没有意义的,因为哈希码实际上并没有任何意义,并且除了学习排序之外没有特殊的理由要按它进行排序。

    这里有一个更好的方法:更改通用列表的规则。现在,您列表中的所有内容都必须是某种东西。为什么不改变它,让它成为某种实现Comparable 接口的东西呢?这样,除了如何比较它们之外,您不需要了解有关对象的任何信息。这在很大程度上是 Java 本身解决这个问题的方式。 (我建议阅读它的收藏品)。

    只需将您的对象从 LList&lt;T&gt; 更改为 LList&lt;T extends Comparable&lt;T&gt;&gt; 即可!

    【讨论】:

    • 效果很好。谢谢。在我得到 Comparable 的东西之后,我只是对 mergeSort 做了一些更改(应该或不应该存在的东西),现在排序正确了。谢谢
    • 澄清一下,您不必修改 LList 类。只需要 LList 或 LList
    • 你的意思是 LList>?
    • 为获得最佳效果,请使用&lt;T extends Comparable&lt;? super T&gt;&gt;
    【解决方案4】:

    您应该使用Comparable 接口。

    Comparable one = (Comparable)first.headNode.data;
    Comparable two = (Comparable)second.headNode.data;
    
    if(one.compareTo(two) < 0)
    {
      ...
    }
    else
    {
      ...
    }
    

    请注意:这很草率。我没有检查 headNode.data 实际上是 Comparable 对象的任何地方。如果是这种情况,我们真的应该抛出一个异常。

    【讨论】:

      【解决方案5】:

      在我制作的 C# 框架中对我有用的东西。为类型化对象创建一个比较器对象,并使用反射来确定列表正在排序的属性的值。根据需要进行调整:

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      
      namespace BOCL
      {
        /// <summary>
        /// Provides a comparer for collections of BOCL objects so they can be compared on any property
        /// </summary>
        /// <typeparam name="T">The type of BOCL object to compare</typeparam>
        public class BusinessBaseComparer<T> : IComparer<T> where T : BusinessBase<T>, new()
        {
          #region Constructors
      
          /// <summary>
          /// Provides a default constructor for the comparer
          /// </summary>
          protected BusinessBaseComparer()
          {
            //An instance of the business base comparer must be declared with at least one argument to be of any use
          }
      
          /// <summary>
          /// Build this comparer sorting on a particular property ascending
          /// </summary>
          /// <param name="property">The property on which the sort should be applied</param>
          public BusinessBaseComparer(PropertyDescriptor property)
          {
            m_SortProperty = property;
          }
      
          /// <summary>
          /// Build this comparer sorting on a particular property
          /// </summary>
          /// <param name="property">The property on which the sort should be applied</param>
          /// <param name="direction">The direction to which the sort should be applied</param>
          public BusinessBaseComparer(PropertyDescriptor property, ListSortDirection direction)
          {
            m_SortProperty = property;
            m_SortDirection = direction;
          }
      
          #endregion
      
          #region SortProperty
      
          private PropertyDescriptor m_SortProperty = null;
      
          /// <summary>
          /// The property on which the type is to be sorted. If the property is not found, the objects are deemed equal
          /// </summary>
          protected PropertyDescriptor SortProperty
          {
            get { return m_SortProperty; }
          }
      
          #endregion
      
          #region SortDirection
      
          private ListSortDirection m_SortDirection = ListSortDirection.Ascending;
      
          /// <summary>
          /// The direction in which the type is to be sorted
          /// </summary>
          protected ListSortDirection SortDirection
          {
            get { return m_SortDirection; }
          }
      
          #endregion
      
          #region IComparer<T> Members
      
          /// <summary>
          /// Performs comparison between to BOCL objects
          /// </summary>
          /// <param name="x">The first object to compare</param>
          /// <param name="y">The second object to compare</param>
          /// <returns>The result of the comparison</returns>
          public int Compare(T x, T y)
          {
            if (SortProperty == null)
              return 0; //we didn't find the property we were supposed to sort on
      
            //set up to get the value of the objects we are comparing against
            IComparable xValue = null;
            IComparable yValue = null;
      
            try
            {
              //now get the value for the x object and value for the y object
              //as something we can compare against
              xValue = (IComparable)SortProperty.GetValue(x);
              yValue = (IComparable)SortProperty.GetValue(y);
      
              //if either property came back null
              if (xValue == null || yValue == null)
                return 0; //treat them as the same
            }
            catch (InvalidCastException)
            {
              return 0; //ran into a proplem trying to convert the object into something we could compare against
            }
      
      
            if (SortDirection == ListSortDirection.Ascending)
              return xValue.CompareTo(yValue);
            else
              return yValue.CompareTo(xValue);
          }
      
          #endregion
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-30
        • 2023-04-03
        • 1970-01-01
        • 2020-02-21
        • 2020-09-20
        • 1970-01-01
        相关资源
        最近更新 更多