Set
Java集合类可以用来存储元素,集合类和数组的区别是:数组元素可以是基本类型的值,也可以是对象的引用;集合只能保存对象的引用。Java集合类主要由Collection和Map接口派生而出。集合大致可分为Set、List、Queue和Map四种体系。
其中Set代表无序,不可重复的集合,是继承自Collection的接口,其下面实现了多个子类。这里学习了2个常用的集合HashSet和TreeSet。
HashSet
HashSet是一个典型的Set接口实现类,当向集合中存入一个数据时,集合会调用该对象的hashCode()方法得到该对象的hashCode值,根据这个值来决定对象在HashSet中的存储位置。他有以下几个特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同。
- 集合可以添加一个null值。
- 不是线程同步的。
- 按Hash算法来存储集合中的元素。Hash算法是一个特定的存储数据的规则,存储的数据按照这个规则得到自己的地址单元,这样在查找的时候,能够根据这个规则快速查找到值的位置,所以查找速度很快。
现在来看看HashSet类的常用方法,我们可以直接new一个HashSet集合,或者用另一个集合来构造HashSet。
HashSet<Integer> set1=new HashSet<>();//直接构造,装载整数类型对象
HashSet<Integer> set2=new HashSet<>(set1); //用set1构造set2
常用方法:
- boolean add(E e):添加元素到集合
- void clear(): 删除所有元素
- boolean contains(Object o):判断集合是否包括制定对象
- Iterator iterator(): 返回该集合元素的迭代器
- boolean remove(Object o): 移除指定元素
遍历集合(遍历时集合不能更改,否则会抛出异常):
- 使用Lambda表达式:
set1.forEach(Object -> System.out.println(Object));//输出集合中所有的对象
- foreach:
for (Integer integer : set1) {
System.out.println(integer);
}
- 迭代器访问集合:
Iterator<Integer> iterator=set1.iterator(); //定义迭代器
while (iterator.hasNext()){
System.out.println(iterator.next());
}
TreeSet
TreeSet是SortedSet接口实现的类,TreeSet采用红黑树的数据结构来存储集合元素,因此可以确保装入集合中的元素处于有序状态。
在向集合中添加元素时,TreeSet会调用元素的compareTo()方法来比较元素之间的大小关系(obj1.compareTo(obj2),若返回值为0,表示两个对象相等;返回值大于0,表示obj1>obj2;返回值小于0,表示obj2>obj1)。
这个方法定义在Comparable接口中,因此,如果要想将元素放在TreeSet中,必须实现该接口的compareTo()方法。否则会抛出异常。
import java.util.TreeSet;
class Test{}
public class Main {
public static void main(String[] args) {
TreeSet<Test> set=new TreeSet<>();
//运行时抛出异常
set.add(new Test());
}
}
Java中一些常用类已经实现了该接口,并提供了比较大小的标准,包括数值类(Integer,Double等)、Character类、String类、Date类等。当我们不重新定义compareTo()方法的规则,利用Java提供的compareTo()方法来进行排序时,就是默认排序;此外,我们可以定义自己的排序规则,对数据进行排序。
- 默认排序:利用系统写好的方法向集合中传入数据。
TreeSet<String> set=new TreeSet<>();
set.add("aef");
set.add("abc");
//输出是有序的
for (String str : set) {
System.out.println(str);
}
- 自定义排序规则:可以通过重写Comparable接口的compareTo方法,或者传入一个Lamdba表达式。
//重写接口方法
import java.util.TreeSet;
class Test implements Comparable<Test>{
private int a;
private String name;
public Test(String name,int a) {
this.name=name;
this.a=a;
}
//重写此方法,让对象按数字a从小到大排序
@Override
public int compareTo(Test o) {
if(this.a>o.a){
return -1;
}else if (this.a<o.a) {
return 1;
}else {
return 0;
}
}
@Override
public String toString() {
return "Test [a=" + a + ", name=" + name + "]";
}
}
public class Main {
public static void main(String[] args) {
TreeSet<Test> set=new TreeSet<>();
set.add(new Test("str1", 2));
set.add(new Test("str1", 1));
for (Test str : set) {
System.out.println(str);
}
}
}
//传入Lambda表达式
import java.util.TreeSet;
class Test {
public int a;
public String name;
public Test(String name,int a) {
this.name=name;
this.a=a;
}
@Override
public String toString() {
return "Test [a=" + a + ", name=" + name + "]";
}
}
public class Main {
public static void main(String[] args) {
TreeSet<Test> set=new TreeSet<>(
(obj1,obj2) -> {
Test o1=(Test)obj1;
Test o2=(Test)obj2;
if(o1.a>o2.a){
return -1;
}else if (o1.a<o2.a) {
return 1;
}else {
return 0;
}
}
);
set.add(new Test("str1", 2));
set.add(new Test("str1", 1));
for (Test str : set) {
System.out.println(str);
}
}
}
由于TreeSet的有序特性,该类增加了一些特殊的方法。
- Object first(): 返回集合的第一个元素。
- Object last(): 返回集合的最后一个元素。
- Object lower(Object e): 返回小于指定元素的最大元素(最大下界)。
- Object higher(Object e): 返回大于指定元素的最小元素(最小上界)。
- SortedSet subSet(Object first,Object last): 返回从first到last的子集合。
那到底什么时候选择不同的集合类呢?HashSet的性能总是比TreeSet好,特别是最常用的添加、查询元素操作,因为TreeSet需要额外的开销来维护集合元素的次序。所以,只有需要保持一个有序的集合时,才使用TreeSet,否则都应该使用HashSet。
上一篇: Hadoop学习-HDFS(1)
下一篇: set