先来看看HashSet和LinkedHashSet的一段测试代码:
package set;
import java.util.HashSet;
import java.util.LinkedHashSet;
public class Test1 {
public static void main(String a[]) {
HashSet<String> set = new HashSet<String>();
set.add("a5");
set.add("a6");
set.add("a7");
set.add("a3");
set.add("a4");
set.add("a");
set.add("a1");
set.add("a2");
System.out.println(set);
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("a5");
linkedHashSet.add("a6");
linkedHashSet.add("a7");
linkedHashSet.add("a3");
linkedHashSet.add("a4");
linkedHashSet.add("a");
linkedHashSet.add("a1");
linkedHashSet.add("a2");
System.out.println(linkedHashSet);
}
}
打印结果:
[a, a1, a2, a3, a4, a5, a6, a7]
[a5, a6, a7, a3, a4, a, a1, a2]
个人对HashSet的无序性理解:
- 前提,对于同一个HashSet来说
- 无序性并不是说一个HashSet对象每次打印时候,顺序是随机的;
- 而是说,当插入一个HashSet对象时,其插入的顺序和存储(打印)的顺序是不一样的。
我们来看看下面具体的测试代码:
package set;
import java.util.HashSet;
import org.apache.commons.lang.builder.CompareToBuilder;
public class HashSetTest {
public static void main(String a[]) {
testcase1: HashSet 里面包含了String对象,
// 因为String已经重写了hashCode(),所以不管插入到HashSet的顺序如何,其存储(打印)顺序是按照hashCode()的实现方式,规定好的
HashSet<String> stringHashSet = new HashSet<String>();
for (int i = 0; i < 5; i++) {
String str = "a" + i;
stringHashSet.add(str);
}
// 每次创建出来的stringHashSet,其打存储(印顺)序不变!
System.out.println(stringHashSet); // (你会发现打印顺序都是升序的,感觉和String的hashCode()的实现方式有关。)
// testcas2: HashSet 里面包含了Cat自定义对象,Cat本身的Comparable功能失效
// 因为Cat没有重写了hashCode(),所以不管插入到HashSet的顺序如何,其存储(打印)顺序是总是随机的!
HashSet<Cat> catHashSet = new HashSet<Cat>();
for (int i = 0; i < 5; i++) {
Cat p = new Cat("c" + i, i);
catHashSet.add(p);
}
// 每次创建出来的catHashSet,存储(打印)的顺序与插入的顺序不同
System.out.println(catHashSet);
System.out.println(catHashSet); // 再次打印同一个对象(catHashSet)的时候,顺序就不会变了
System.out.println(catHashSet); // 再次打印同一个对象(catHashSet)的时候,顺序就不会变了
/ testcas3: HashSet 里面包含了Person自定义对象,Person本身的Comparable功能失效
// 因为Person已经重写了hashCode(),所以不管插入到HashSet的顺序如何,其存储(打印)顺序是按照hashCode()的实现方式,规定好的
HashSet<Person1> personHashSet = new HashSet<Person1>();
for (int i = 0; i < 5; i++) {
Person1 p = new Person1("p" + i, i);
personHashSet.add(p);
}
// 每次创建出来的personHashSet,其打存储(印顺)序不变!
System.out.println(personHashSet);// (你会发现打印顺序都是固定顺序的,感觉和Person的hashCode()的实现方式有关。)
}
}
class Cat implements Comparable<Cat> {
public Cat(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
private String name;
private Integer age;
@Override
public int compareTo(Cat o) {
CompareToBuilder ctb = new CompareToBuilder();
ctb = ctb.append(this.getName(), o.getName()).append(this.getAge(), o.getAge());
return 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Cat [name=" + name + ", age=" + age + "]";
}
}
class Person implements Comparable<Person> {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
private String name;
private Integer age;
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
CompareToBuilder ctb = new CompareToBuilder();
ctb = ctb.append(this.getName(), o.getName()).append(this.getAge(), o.getAge()); // ASC
// 升序
return ctb.toComparison();
}
}
LinkedHashSet
是有序的,与HashSet比较来说,插入的顺序和存储(打印)的顺序是一样的
TreeSet
保证集中的元素是有序的,有2种方法可以实现对象之间的可比较性:
1,添加到TreeSet的对象实现了Comparable接口
2,给规则集的元素指定一个比较器(Comparator)
具体实现如下:
package set;
import java.util.Comparator;
import java.util.HashSet;
import java.util.TreeSet;
import org.apache.commons.lang.builder.CompareToBuilder;
public class TreeSetTest {
public static void main(String a[]) {
HashSet<Person> hashSet = new HashSet<Person>();
for (int i = 0; i < 5; i++) {
Person p = new Person("a" + i, i);
hashSet.add(p);
}
System.out.println(hashSet);
// 使用TreeSet无参的构造方法,则应用Person实现Comparable接口的compareTo()
TreeSet<Person> treeSet = new TreeSet<Person>();
for (int i = 0; i < 5; i++) {
Person p = new Person("a" + i, i);
treeSet.add(p);
}
System.out.println(treeSet);
// TreeSet 如果想应用Comparator
// 得在构造方法传入,这样一来Person实现Comparable接口的compareTo()方法,就失效了
// 这一点和List使用Comparator不同: Collections.sort(personList, new
// PersonComparator<Persion>());
treeSet = new TreeSet<Person>(new PersonComparator());
for (int i = 0; i < 5; i++) {
Person p = new Person("a" + i, i);
treeSet.add(p);
}
System.out.println(treeSet);
}
}
class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
// 这里使用org.apache.commons.lang.builder.CompareToBuilder,非常好用哦!!!!!
CompareToBuilder ctb = new CompareToBuilder();
ctb = ctb.append(o2.getName(), o1.getName()).append(o2.getAge(), o1.getAge()); // DESC
// 降序
// ctb = ctb.append(o1.getName(), o2.getName()).append(o1.getAge(),
// o2.getAge()); // ASC 升序:注意 o1 o2的先后顺序的变化
return ctb.toComparison();
}
}
class Person1 implements Comparable<Person1> {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person1 other = (Person1) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
private String name;
private Integer age;
public Person1(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public int compareTo(Person1 o) {
CompareToBuilder ctb = new CompareToBuilder();
ctb = ctb.append(this.getName(), o.getName()).append(this.getAge(), o.getAge()); // ASC
// 升序
return ctb.toComparison();
}
}