比较通用列表中的元素

时间:2009-04-09 02:01:50

标签: java generics

我今年早些时候为我的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)

5 个答案:

答案 0 :(得分:6)

请注意,Comparable也是一种泛型类型,可通过与其相媲美的类型进行参数化。上面声明mergeSort函数的最常用,类型安全的方法是:

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

这强制类型T的compareTo方法可以接受类型为T的参数。(理论上,类型可以实现Comparable,但不能与自身相比,如SomeClass implements Comparable<CompletelyDifferentClass>,所以重要的是对可比较类型参数的要求。然而,在实践中,任何设计良好的可比较类都应至少与其本身相当。)

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

答案 1 :(得分:4)

查看ComparatorComparable接口。

您的排序方法应该采用Comparator,或者您应该指定&lt; T扩展可比较&gt;以便可以使用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) {
    ...
}

答案 2 :(得分:3)

好吧,正如你所发现的,你有一个问题。您对列表中对象的所有了解都是它们是Object的实例或其子类之一。你不能真正排序对象。您现在有几个选择:

您拥有的一个选项是对完全没有意义的东西进行排序,例如对象的hashCode。事实上,您可以使用hashCode实现一个完全有效的mergesort,但它基本上没有意义,因为哈希代码实际上并不意味着什么,除了了解排序之外没有特别的理由对它进行排序。

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

只需将您的对象从LList<T>更改为LList<T extends Comparable<T>>,就可以了!

答案 3 :(得分:1)

您应该使用Comparable界面。

Comparable one = (Comparable)first.headNode.data;
Comparable two = (Comparable)second.headNode.data;

if(one.compareTo(two) < 0)
{
  ...
}
else
{
  ...
}

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

答案 4 :(得分:1)

我在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
  }
}