因为Set集合的API方法和Collection集合一模一样。故没有没有它的特殊的方法。
所以我们只要学它的两个子类,一个HashSet和另外一个TreeSet
实现Set接口,由哈希表(实际是一个hashmap对象)支持,它不保证set的迭代顺序;特别是它不保证该顺序恒久不变。此类允许下使用null元素。
案例:
HashSet<String> hashSet =new HashSet<String>();
boolean b1 = hashSet.add("a");
boolean b2= hashSet.add("a");
boolean b3= hashSet.add("b");
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
System.out.println(hashSet);
//HashSet的继承体系中有重写toString方法
for (String string : hashSet) {
System.out.println(string);
//只要使用那个迭代器迭代,那么就可以使用foreach循环
}
效果如下:
tips:Set集合无索引,不可以重复,无序(存储不一致)它的继承系统中有toString方法,故不需要书写toString()方法。
存储自定义对象,并保证元素唯一性。
例:
注意因为set集合不保证元素的有序性,所以每次存储都是无序的
HashSet<Person> hashSet =new HashSet<Person>();
hashSet.add(new Person("张三",12));
hashSet.add(new Person("张三",12));
hashSet.add(new Person("李四",13));
hashSet.add(new Person("李四",13));
hashSet.add(new Person("李四",13));
System.out.println(hashSet);
效果如下:
当我们重写equals方法,使我们出现的姓名和年龄相同就表示存储人物相同。但是在Set集合中我们并不能用equals方法进行判断。而是先要设置hasCode的值。
@Override
public boolean equals(Object obj) {
Person person =(Person)obj;
return this.name.equals(person.name) &&this.age ==person.age;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return 10;
}
当hasCode返回值相同时,说明我们内存中的存储的某类对象会处在相同位置。然后才会调用equals方法,使用equas方法进行判断如果我们的姓名和年龄相同则返回true,不进行对象存储。如果返回false,则会采用筒状式,将对象存储起来。如图所示:
但是为了保证程序的效率,我们尽可能的保证hasCode不相同,然后再执行equals方法。当然如果属性值相同的化,那么它的hasCode的值必然是相同的。属性不相同的返回值尽可能不同。Eclipse等编译器可以自动帮我们生成代码块。快捷键:ctrl+shifts +h 即可生成。并且我们勾选判断的属性。画图如下:
@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 != 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 int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
注意该处为什么prime是31?
好处:31是一个质数,质数是能被1和自己本身整除的数。并且31不大也不小。
1.HashSet原理(重点)
2.将自定义类的对象存入HashSet去重复
LinkedHashSet概述:
LinkedHashSet<String> linkedHashSet =new LinkedHashSet<String>();
linkedHashSet.add("a");
linkedHashSet.add("a");
linkedHashSet.add("a");
linkedHashSet.add("b");
linkedHashSet.add("b");
linkedHashSet.add("c");
linkedHashSet.add("d");
System.out.println(linkedHashSet);
TreeSet是用来对元素进行排序的,并且它也是不存储相同数据的。
TreeSet<Integer> treeSet =new TreeSet<Integer>();
treeSet.add(1);
treeSet.add(1);
treeSet.add(3);
treeSet.add(3);
treeSet.add(2);
treeSet.add(2);
treeSet.add(4);
System.out.println(treeSet);
当我们单纯的去存储对象的时候,会进行报错。因为对象不能用来做比较。所以我们需要给我们bean类添加接口方法。
public class Person implements Comparable<Person>{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return 1;
}
}
TreeSet部分
TreeSet<Person> treeSet =new TreeSet<Person>();
treeSet.add(new Person("张三",12));
treeSet.add(new Person("李四",12));
treeSet.add(new Person("王五",13));
treeSet.add(new Person("赵六",14));
System.out.println(treeSet);
效果如下:
注意:CompareTo方法的返回值:
如果return返回的数是正数
,集合就是怎么存怎么取
。
如果return返回的数是负数
,集合就是倒序存储
。
如果return返回的数是0
,集合中就存在一元素
。
书写Bean包中的Person实体类
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return this.age -o.age;
}
TreeSet<Person> treeSet =new TreeSet<Person>();
treeSet.add(new Person("张三",12));
treeSet.add(new Person("李四",22));
treeSet.add(new Person("周七",24));
treeSet.add(new Person("王五",10));
treeSet.add(new Person("赵六",24));
System.out.println(treeSet);
原理如下:
效果如下:
此时我们会发现,少一个赵六的元素,很简单,因为我们只进行了年龄判断,所以后面存储的年龄相同的元素不会被存储进来。
如果我们进行升级:按照年龄进行排序
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
int num =this.age -o.age;
return num == 0? this.name.compareTo(o.name):num;
}
该方法会进行完整的排序。
@Override
public int compareTo(Person o) {
int num = this.name.compareTo(o.name);
//按照姓名排序
return num== 0? this.age -o.age :num;
//年龄是次要条件
}
TreeSet<Person> treeSet =new TreeSet<Person>();
treeSet.add(new Person("李四",22));
treeSet.add(new Person("张三",12));
treeSet.add(new Person("周七",24));
treeSet.add(new Person("王五",10));
treeSet.add(new Person("赵六",24));
System.out.println(treeSet);
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
int length =this.name.length() - o.name.length();
//比较姓名长度
int num =length == 0 ?this.name.compareTo(o.name):length;
//完全有一种可能,名字长度一样,内容是不一样的
return num==0? this.age -o.age:num;
//完全有一种可能,姓名和长度均相同
}
TreeSet(Collection super E> comparator)
:构造一个新的空TreeSet,他根据指定比较器进行排序
需求:将字符串按照长度排序
TreeSet<String> treeSet =new TreeSet<String>(new CompareByLen());
//Comparator c = new CompareByLen();
treeSet.add("aaaaaaaaaa");
treeSet.add("z");
treeSet.add("wc");
treeSet.add("nba");
treeSet.add("cba");
System.out.println(treeSet);
新建一个类
class CompareByLen implements Comparator<String>{
@Override
public int compare(String s1, String s2) {
//按照字符串的长度比较
// TODO Auto-generated method stub
int num = s1.length() -s2.length();
//长度为主要条件
return num==0? s1.compareTo(s2): num ;
//内容为次要条件
}
}
依次从左边就先取出,如果没有的话就取出其右边。
1.特点
TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
2.使用方式
a.自然顺序(Comparable)
b.比较器顺序(Comparator)
c.两种方式的区别