使用Collections.sort时 - 不存在变量T的实例,以便Collection符合等

时间:2018-02-20 15:24:45

标签: java sorting generics collections

所以我构建了这两个类:  1.实现可比较的类型  2. GenreManager,它采用类型集合并创建它的内部副本。稍后在GenreManager中,我需要通过获取名称作为输入来添加新的类型,并且我需要为该类型分配下一个空闲ID号,这基本上是在最小的使用id之后的下一个最小正数。

我正在尝试使用Collections.sort()对我的列表进行排序,但是我收到以下错误: "没有类型变量T的实例,以便Collection符合List。"而且我不确定这是指什么...我已经尝试在这里准备了一些关于此的帖子,但无法找出解决方案......以下是代码的一部分:

public class Genre implements Comparable<Genre>{

    private int id;
    private String name;

    public Genre(int id, String name){
        this.id = Validate.requireNonNegative(id);
        this.name = Validate.requireNonNullNotEmpty(name);
    }

    @Override
    public int compareTo(Genre o) {
        int res = Integer.valueOf(id).compareTo(o.id);
        if (res != 0){
            return res;
        }
        else{
            return this.name.compareToIgnoreCase(o.name);
        }
    }
 }

public class GenreManager{

    private Collection<Genre> genres;
    private Collection<Genre> sortedTree;

    public GenreManager(){
        this.genres = new ArrayList<Genre>();
    }

    public GenreManager(Collection<Genre> genres){
        // check for duplicates
        for (Genre x : genres){
            for (Genre y : genres){
                if (x.equals(y) || x.getName().equals(y.getName()))
                    throw new IllegalArgumentException("List contains duplicates");
            }
        }

        this.genres = new ArrayList<Genre>(Collections.sort(genres));    
    }
}

我正在尝试在上面的构造函数中进行排序。有人能告诉我如何解决这个问题吗?

我试过玩一下,尝试将私有变量从Collection<Genre>更改为List<Genre>,例如类似的东西,但没有任何效果......我也试过转换.sort的输入方法(List<Genre>),但它也没有工作。

PS:我无法更改任何方法标题或类标题。

谢谢!

2 个答案:

答案 0 :(得分:0)

如前所述,您的代码有几个错误,使其无法使用:

  1. 自行检查元素的相等性。

  2. Collections.sort方法将List of Comparable作为参数,当Collection在层次结构中略高时,这意味着您不能将其用作参数。要解决此问题,请将变量类型的声明更改为List。

  3. 方法Collections.sort返回void,因此您无法将其返回值作为参数传递给ArrayList构造函数。相反,首先尝试分配genres变量,然后通过Collections.sort将其排序为
  4. this.genres = new ArrayList/LinkedList(genres) Collections.sort(this.genres)

    同样,您可以考虑使用TreeSet,因为它包含所有已排序且没有重复的元素,因此您的构造函数将看起来像

    this.genres = new TreeSet(genres)

    此外,即使在添加过程中也可以防止重复,因此如果您有10个元素,则添加已存在的元素将不会对您的集进行任何更改。但是使用这个数据结构,你应该在添加之前检查变量为null,因为它会产生NullPointerException

答案 1 :(得分:0)

根据要求,这是我对回答问题的评论的汇编:

当前问题是Collections.sort(List<T>)采用List参数而不仅仅是Collection,因为通常不需要对集合进行排序(例如,散列集不是)。此外,该方法返回void并对传递的列表进行排序,即您调用它的方式将无法编译。

考虑到所有这些因素,您的代码可能会更改为:

public class GenreManager{
   private List<Genre> genres;
   ...

   public GenreManager(Collection<Genre> genres){
     ... 

     //create a list out of the passed collection
     this.genres = new ArrayList<Genre>( genres );

     //sort the list    
     Collections.sort(this.genres);
   }
}

您发布的代码的另一个问题是,对于任何非空集合,它将抛出IllegalArgumentException因为元素与自身进行比较。在条件中添加x != y的检查可以解决这个问题,但代码仍然有点慢,因为它的时间复杂度为O(n 2 )。

这可以解决使用集合而不是列表。但是,HashSet取决于equals()hashCode()如何定义相等性,这似乎与您的要求不符。这可以通过使用根据需要实现两种方法的包装器对象来解决。

更好的方法可能是使用TreeSetTreeSet使用比较来确定顺序和相等性(如果比较结果为0),从而允许您让Genre类实现Comparable,或者提供单独的Comparator 1}}(例如,如果你需要多个不同的相等定义)。

如果您只想消除重复项,那么您的代码可能如下所示:

public class GenreManager{
   private SortedSet<Genre> genres;
   ...

   public GenreManager(Collection<Genre> genres){
     this.genres = new TreeSet<>( genres );
   }
}

如果您想知道集合中有哪些重复项,您可以这样做:

public GenreManager(Collection<Genre> genres){
  this.genres = new TreeSet<>(); //the generic type is inferred from this.genres

  for( Genre element : genres ) {
    //If the element didn't exist in the set add() will return true, false if it existed  
    boolean nonDuplicate = this.genres.add( element );

    //handle the duplicate element here
  }
}