文章目录
上文介绍了List接口的实现类,本文来介绍Set和Map
点击这里跳转到上一篇,java基础 之 集合与栈的使用(一)
List 和 Set的比较
List | Set | |
---|---|---|
有序性 | 保证按插入顺序排序 | 存储和取出顺序不一致 |
唯一性 | 可以重复 | 元素唯一 |
获取元素 | 可以根据索引值操作或者获取元素 | 不能根据索引值操作 |
Set接口
对于set的无序该怎么理解?
- 无序是指读取数据的顺序不一定和插入数据的顺序一样
(一)实现类:HashSet
特点
- HashSet底层使用的是HashMap
- 不保证元素的顺序,
- 数据不能有重复的
- 元素值允许有NULL
- 线程不安全
HashSet集合的一些方法
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
public class TestHashSet {
public static void main(String[] args) {
HashSet set = new HashSet<>();
Random random = new Random();
for(int i=0;i<20;i++){
// add(Object o):向Set集合中添加元素,不允许添加重复数据。
System.out.print(set.add(random.nextInt(15))+" ");
}
// size():返回Set集合中的元素个数
System.out.println(set.size());
//.contains(Object o):判断集合中是否包含obj元素。
System.out.println(set.contains(23));
//.remove(Object o): 删除Set集合中的obj对象,删除成功返回true,否则返回false。
System.out.println(set.remove(23));
//.isEmpty():如果Set不包含元素,则返回 true。
System.out.println(set.isEmpty());
// 打印set中内容,方法一:迭代法
Iterator<Integer> iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+"-- ");
}
// 打印set中内容看,方法二:foreach
for (Object o : set) {
System.out.print(o+" ");
}
// .clear(): 移除此Set中的所有元素。返回类型为void
set.clear();
}
}
(二)实现类:LinkedHashSet
LinkedHashSet 特点
- 继承了HashSet,是在HashSet的基础上维护了元素添加顺序的功能
- LinkedHashSet是List接口的一个实现类
- 底层使用的是HashSet,同时使用链表维护元素的插入顺序
- 元素有序且唯一,因为链表保证了元素有序,哈希表保证元素唯一
- LinkedHashSet线程不安全
LinkedList集合的一些方法
LinkedHashSet继承于HashSet,它的源码很少,只有几个构造函数,基本上都是调用父类HashSet的构造函数。
方法同HashSet,这里就不写了。
【代码部分】HashSet 和 LinkedHashSet
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Random;
public class TestLinkedHashSet {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
LinkedHashSet linkedHashSet = new LinkedHashSet();
Random random = new Random(1);
System.out.println("添加的数字内容:");
for(int i=0;i<20;i++){
int element = random.nextInt(15);
System.out.print(element+" ");
hashSet.add(element);
linkedHashSet.add(element);
}
System.out.println();
Iterator hash = hashSet.iterator();
System.out.println("set集合打印:");
while(hash.hasNext()){
System.out.print(hash.next()+" ");
}
System.out.println();
System.out.println("linkedSet集合打印:");
Iterator linked = linkedHashSet.iterator();
while (linked.hasNext()){
System.out.print(linked.next()+" ");
}
System.out.println();
System.out.println("---------------------------------");
HashSet<String> setString = new HashSet();
LinkedHashSet<String> linkedString= new LinkedHashSet();
System.out.println("添加的字母内容:");
for(int i=0;i<20;i++){
char letter = (char) ('a'+random.nextInt(26));
System.out.print(letter+" ");
setString.add(String.valueOf(letter));
linkedString.add(String.valueOf(letter));
}
Iterator s_setString = setString.iterator();
System.out.println();
System.out.println("set集合打印:");
while(s_setString.hasNext()){
System.out.print(s_setString.next()+" ");
}
System.out.println();
System.out.println("linkedSet集合打印:");
Iterator linked_setString = linkedString.iterator();
while (linked_setString.hasNext()){
System.out.print(linked_setString.next()+" ");
}
}
}
代码的运行结果是否跟自己想象中的一样?
不一样的话,知道是怎么回事不?
浅谈HashSet 和 LinkedHashSet的打印结果
疑问一:set的无序是怎么回事?
集合所说的序,是指元素存入集合的顺序,当元素存储顺序和取出顺序一致时就是有序,否则就是无序。
疑问二:为什么HashSet打印的值是有序的?
HashSet真实的情况是有序的,只不过它是通过内部HashCode方法计算hash值后自动进行了排序,所以读取的是经过内部排序后的数据,且此数据每次结果都是一样的顺序。
疑问三:HashSet打印的值一直是有序的吗?
如果添加的是Integer类型的,打印出来一直是有序的,因为Integer类型hashCode()的返回值就是其int值本身
如果添加的不是Integer类型的,当数组长度小于16时,打印出来是无序的,大于等于16就是有序的,与扩容机制有关。
(点击这里了解为啥16是分界线)Java遍历HashSet为什么输出是有序的?
(三)实现类: TreeSet
特点
- TreeSet内部使用的是TreeMap,TreeMap是基于红黑树实现的
- 插入数据内部有两种排序方法:自然排序 和 定制排序
- TreeSet会对插入的数据排序,所以输入和输出顺序不一致
- 值唯一,但是不可以为null
- 线程不安全
TreeSet集合的使用
输出时排序是按照字典序排序的方式
public class TestTreeSet { public static void main(String[] args) { TreeSet ts=new TreeSet(); ts.add("hello"); ts.add("world"); ts.add("abc"); Iterator it=ts.iterator(); // 输出 : 按照字典序排序的方式进行排序 while(it.hasNext()) { System.out.print(it.next()); // 输出结果:abd hello world } } }
字典序排序是一种按照字母表的顺序对字符串进行排序的方法。 其基本原理是在比较两个字符串时,从左到右逐个字符进行比较。如果某个位置的字符不同,则较小的字符排在前面;如果所有字符都相同,则较短的字符串排在前面。
如果插入的是自定义对象 需要让类实现 Comparable 接口并且必须要重写compareTo
/***创建一个Person类 */ public class Person implements Comparable{ String name; int age; Person(String name,int age) { this.name=name; this.age=age; } @Override public int compareTo(Object o) { Person p=(Person)o; //先对姓名字典序比较 如果相同 比较年龄 if(this.name.compareTo(p.name)!=0) { return this.name.compareTo(p.name); } else { if(this.age>p.age) return 1; else if(this.age<p.age) return -1; } return 0; } }
import java.util.Iterator; import java.util.TreeSet; public class TestTreeSet { public static void main(String[] args) { TreeSet treeSet=new TreeSet(); treeSet.add(new Person("hello",21)); treeSet.add(new Person("world",12)); treeSet.add(new Person("abc",8)); treeSet.add(new Person("Abc",12)); Iterator it=treeSet.iterator(); while(it.hasNext()) { Person p=(Person)it.next(); System.out.println(p.name+":"+p.age); } } } ----------------运行结果----------------- Abc:12 abc:8 hello:21 world:12
总结
1、HashSet:HashSet的性能基本上比LinkedHashSet和TreeSet要好,特别是添加和查询,这也是用的最多的两个操作
2、LinkedHashSet的查询稍慢一些,但是他可以维持元素的添加顺序。所以只有要求当插入顺序和取出顺序一致的时候 才使用LinkedHashSet。
3、TreeSet只有在需要对元素进行排序时使用