关于集合类运用Comparator排序的问题!

问题描述:

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;


class User {
    
    private String name;
    private String age;
    private String grade;
    public User(String name, String age, String grade) {
        super();
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getGrade() {
        return grade;
    }
    public void setGrade(String grade) {
        this.grade = grade;
    }
    
    public String toString(){
        return name+"["+age+"] :"+grade;
    }
    
    public static void main(String[] args) {
        Set users=new TreeSet(new Comparator(){
            public int compare(Object o1, Object o2) {
                User user1=(User)o1;
                User user2=(User)o2;
                if(user1.getName().equals(user2.getName())&&user1.getAge().equals(user2.getAge())){
                    return 0;
                }
                int flag=user1.getGrade().compareTo(user2.getGrade());
                if(flag==0){
                    flag=user1.getName().compareTo(user2.getName());
                    if(flag==0){
                        return user1.getAge().compareTo(user2.getAge());
                    }
                }
                return flag;
            }
        });
        
        users.add(new User("billx","23","90"));
        users.add(new User("bill","23","180"));
        users.add(new User("are","23","200"));
        
        System.out.println(users);
    }
}

 上面代码执行的结果是:[bill[23] :180, are[23] :200, billx[23] :90]

可是我期望的结果是:[billx[23] :90,bill[23] :180, are[23] :200 ]

题目的需求是依据用户信息排序如果用户名和年龄相同认为是同一用户,集合内用户不重复,按照成绩,姓名,年龄升序排列答应出用户信息!

请问我上面哪边错了 ,应该怎么写????

 


问题补充:
我没有注意注意类型无语了,请问如果是从一个大的文本文件中获取用户信息需要如何改动才能够提高性能!!!
问题补充:
这个问题并没有结束,因为我在测试的时候,有时用户名和年龄相等时,任然会显示出来,我想说的是User对象是不是还要overload hashcode和equals方法呢,不然光用户名和年龄相等时并不会认为是同一个用户!~!!

这边也发出来好了……

TreeSet背后是TreeMap,它上面的put方法对comparator和comparable是分开处理的:
[code] // split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
//...[/code]
也就是说构造的时候给了comparator就够了。TreeMap不使用hash所以覆盖hashCode没啥可见的作用。

问题是出在你的排除条件不适合使用TreeSet。之所以会有元素重复加到TreeSet里,是因为像这样:
如果现在set里的顺序是:[a, b]
接下来要加入c,它首先跟b比较,发现比b“大”,于是插入到b的后面,变成:[a, b, c]
但如果a与c实际上属于“相等”的情况,那它们连比较的机会都没得到。

所以说你的使用场景不适合TreeSet。你可以选择实现hashCode然后用HashSet,都加好了之后重复的元素就都没了,然后再从那个HashSet创建一个TreeSet出来,就有顺序了。

[code="java"]import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

class User {
private String name;
private String age;
private String grade;
public User(String name, String age, String grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}

public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name).append("[").append(age).append("] :").append(grade);
    return sb.toString();
}

public static void main(String[] args) {
    Set<User> users = new TreeSet<User>(new Comparator<User>() {
        public int compare(User user1, User user2) {
            int g1 = Integer.parseInt(user1.getGrade());
            int g2 = Integer.parseInt(user2.getGrade());
            int gradeDiff = g1 - g2;
            if (0 != gradeDiff) return gradeDiff;

            int nameOrder = user1.getName().compareTo(user2.getName());
            if (0 != nameOrder) return nameOrder;

            int a1 = Integer.parseInt(user1.getAge());
            int a2 = Integer.parseInt(user2.getAge());
            int ageDiff = a1 - a2;
            if (0 != ageDiff) return ageDiff;

            return 0;
        }
    });

    users.add(new User("billx", "23", "90"));
    users.add(new User("bill",  "23", "180"));
    users.add(new User("are",   "23", "200"));

    System.out.println(users);
}

}[/code]
楼主是想要这样么?每次比较的时候都要把字符串解析成数字,效率会比较不好。不如一开始就在User里把age和grade保存为int?

抱歉,看漏条件了。如果用户名和年龄相等就被认定是同一个用户的话,那就把条件加上去就是:
[code="java"]Set users = new TreeSet(new Comparator() {
public int compare(User user1, User user2) {
if (user1.getName().equals(user2.getName())
&& user1.getAge().equals(user2.getAge())) return 0;

    int g1 = Integer.parseInt(user1.getGrade());
    int g2 = Integer.parseInt(user2.getGrade());
    int gradeDiff = g1 - g2;
    if (0 != gradeDiff) return gradeDiff;

    int nameOrder = user1.getName().compareTo(user2.getName());
    if (0 != nameOrder) return nameOrder;

    int a1 = Integer.parseInt(user1.getAge());
    int a2 = Integer.parseInt(user2.getAge());
    int ageDiff = a1 - a2;
    if (0 != ageDiff) return ageDiff;

    return 0;
}

});[/code]

从文件获取用户信息跟User类如何设计关系不是很大。User类的设计主要是影响到后续的使用,就像上面的例子。我是建议把age和grade改成int类型的。创建User实例的时候就把字符串转成整数。