Java容器Set接口
Set接口的实现,可以方便地将指定的类型以集合类型保存在一个变量中。Set是一个不包含重复元素的Collection,更确切地讲,Set 不包含满足 e1.equals(e2) 的元素对,并且最多包含一个 null 元素。Set接口的底层存储实现都是依赖Map的实现,也可以说Set中元素的管理就是对Map中key的管理。下面简单描述一下各种Set接口的实现类,主要包括HashSet,LinkedHashSet,TreeSet
1、HashSet
HashSet底层是有HashMap实现的,存储的是[key-Object常量]这样的键值对,同样包括initialCapacity和loadFactor两个参数,这两个参数的意义和HashMap一样,都是比较重要的。另外,HashSet集合里边的元素是无序的。
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L; private transient HashMap<E,Object> map; // Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object(); /**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<E,Object>();
} /**
* Constructs a new set containing the elements in the specified
* collection. The <tt>HashMap</tt> is created with default load factor
* (0.75) and an initial capacity sufficient to contain the elements in
* the specified collection.
*
* @param c the collection whose elements are to be placed into this set
* @throws NullPointerException if the specified collection is null
*/
public HashSet(Collection<? extends E> c) {
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + , ));
addAll(c);
} /**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* the specified initial capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<E,Object>(initialCapacity, loadFactor);
}
2、LinkedHashSet
LinkedHashSet继承了HashSet,但它底层存储使用的是LinkedHashMap,所以其中的元素是按照插入有序的。看LinkedHashSet类只是定义了四个构造方法,也没看到和链表相关的内容,为什么说LinkedHashSet内部使用链表维护元素的插入顺序(插入的顺序)呢?点进去看下这个三个参数的构造方法HashSet(int initialCapacity, float loadFactor, boolean dummy),就会发现使用的实现类是LinkedHashMap了:
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable { private static final long serialVersionUID = -2851667679971038690L; /**
* Constructs a new, empty linked hash set with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity of the linked hash set
* @param loadFactor the load factor of the linked hash set
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
} /**
* Constructs a new, empty linked hash set with the specified initial
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity of the LinkedHashSet
* @throws IllegalArgumentException if the initial capacity is less
* than zero
*/
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
} /**
* Constructs a new, empty linked hash set with the default initial
* capacity (16) and load factor (0.75).
*/
public LinkedHashSet() {
super(16, .75f, true);
}
/**
* Constructs a new, empty linked hash set. (This package private
* constructor is only used by LinkedHashSet.) The backing
* HashMap instance is a LinkedHashMap with the specified initial
* capacity and the specified load factor.
*
* @param initialCapacity the initial capacity of the hash map
* @param loadFactor the load factor of the hash map
* @param dummy ignored (distinguishes this
* constructor from other int, float constructor.)
* @throws IllegalArgumentException if the initial capacity is less
* than zero, or if the load factor is nonpositive
*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}
3、TreeSet
TreeSet底层存储使用的是TreeMap,使用它可以从Set中提取有序的序列,元素必须实现Comparable接口否则按默认字典排序。
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
/**
* The backing map.
*/
private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object(); /**
* Constructs a set backed by the specified navigable map.
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
} /**
* Constructs a new, empty tree set, sorted according to the
* natural ordering of its elements. All elements inserted into
* the set must implement the {@link Comparable} interface.
* Furthermore, all such elements must be <i>mutually
* comparable</i>: {@code e1.compareTo(e2)} must not throw a
* {@code ClassCastException} for any elements {@code e1} and
* {@code e2} in the set. If the user attempts to add an element
* to the set that violates this constraint (for example, the user
* attempts to add a string element to a set whose elements are
* integers), the {@code add} call will throw a
* {@code ClassCastException}.
*/
public TreeSet() {
this(new TreeMap<E,Object>());
}
总结一下:
HashSet是为快速查找而设计的Set,存入HashSet的元素必须定义hashCode();LinkedHashSet具有HashSet的查询速度,且内部使用链表维护元素的顺序(插入顺序),在使用迭代器遍历Set时,结果会按插入的次序显示,元素必须定义hashCode()方法;TreeSet保存次序的Set,底层为树结构,使用它可以从Set中提取有序的序列,元素必须实现Comparable接口。
另外,这里提一下hashcode和equals在Set中的比较重要的意义。当对以哈希为底层的集合操作的时候,会先以hashcode去找对应的链表,然后再遍历对应的链表通过equals对比key,最后找到对应的value。还是和上次说的一样,当hashcode方法设计的不好的时候,会导致元素分布不均匀,然后调用大量的equals对比key,最后影响到程序的执行效率。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
} modCount++;
addEntry(hash, key, value, i);
return null;
}
最后提一下面试比较常问到的问题:当两个对象的hashcode相等的时候它们的equals不一定返回true;但当两个对象的equals返回true的时候它们的hashcode一定相同。
Java容器Set接口的更多相关文章
- Java容器Map接口
Map接口容器存放的是key-value对,由于Map是按key索引的,因此 key 是不可重复的,但 value 允许重复. 下面简单介绍一下Map接口的实现,包括HashMap,LinkedHas ...
- Java容器List接口
List接口是Java中经常用到的接口,如果对具体的List实现类的特性不了解的话,可能会导致程序性能的下降,下面从原理上简单的介绍List的具体实现: 可以看到,List继承了Collection接 ...
- Java容器---Collection接口中的共有方法
1.Collection 接口 (1)Collection的超级接口是Iterable (2)Collection常用的子对象有:Map.List.Set.Queue. 右图中实现黑框的ArrayLi ...
- Java容器——List接口
1. 定义 List是Collection的子接口,元素有序并且可以重复,表示线性表. 2. 常用实现类 ArrayList:它为元素提供了下标,可以看作长度可变的数组,为顺序线性表. LinkedL ...
- java容器——Collection接口
Collection是Set,List接口的父类接口,用于存储集合类型的数据. 2.方法 int size():返回集合的长度 void clear():清除集合里的所有元素,将集合长度变为0 Ite ...
- Java容器——Set接口
1.定义 set中不允许放入重复的元素(元素相同时只取一个).它使用equals()方法进行比较,如果返回true,两个对象的HashCode值也应该相等. 2.方法 TreeSet中常用的方法: b ...
- Java容器——Map接口
1.定义 Map用于保存存在映射关系<key, value>的数据.其中key值不能重复(使用equals()方法比较),value值可以重复. 2.常用实现类 HashMap:和Hash ...
- Java容器深入浅出之Collection与Iterator接口
Java中用于保存对象的容器,除了数组,就是Collection和Map接口下的容器实现类了,包括用于迭代容器中对象的Iterator接口,构成了Java数据结构主体的集合体系.其中包括: 1. Co ...
- 【Java心得总结七】Java容器下——Map
我将容器类库自己平时编程及看书的感受总结成了三篇博文,前两篇分别是:[Java心得总结五]Java容器上——容器初探和[Java心得总结六]Java容器中——Collection,第一篇从宏观整体的角 ...
随机推荐
- 第九周(11.11-11.17)----Beta版本视频发布
beta阶段视频发布地址: http://v.youku.com/v_show/id_XMTgxNjE2NzY3Mg==.html
- java 调用 oracle的function 和 procedure
1.调用函数 CallableStatement cs=con.prepareCall("{?=call get_pname(?,?,?)}"); 第一个?表示返回的值,后面的?可 ...
- [转帖] Linux buffer 和 cache相关内容
Linux中Buffer/Cache清理 Lentil2018年9月6日 Linux中的buff/cache可以被手动释放,释放缓存的代码如下: https://lentil1016.cn/linux ...
- ACM数论之旅3---最大公约数gcd和最小公倍数lcm(苦海无边,回头是岸( ̄∀ ̄))
gcd(a, b),就是求a和b的最大公约数 lcm(a, b),就是求a和b的最小公倍数 然后有个公式 a*b = gcd * lcm ( gcd就是gcd(a, b), ( •̀∀•́ ) ...
- Python多线程获取返回值
在使用多线程的时候难免想要获取其操作完的返回值进行其他操作,下面的方法以作参考: 一,首先重写threading类,使其满足调用特定的方法获取其返回值 import threading class M ...
- ADO.NET:C#/SQL Server
1.首次要准备的(工具)是:a.Microsoft Visual Studio Ultimate 2012;b.Microsoft SQL Server Management Studio ; 2.首 ...
- Go 示例测试实现原理剖析
简介 示例测试相对于单元测试和性能测试来说,其实现机制比较简单.它没有复杂的数据结构,也不需要额外的流程控制,其核心工作原理在于收集测试过程中的打印日志,然后与期望字符串做比较,最后得出是否一致的报告 ...
- RocketMQ生产者消息篇
系列文章 RocketMQ入门篇 RocketMQ生产者流程篇 RocketMQ生产者消息篇 前言 上文RocketMQ生产者流程篇中详细介绍了生产者发送消息的流程,本文将重点介绍发送消息的通信模式以 ...
- 【CF472G】Design Tutorial: Increase the Constraints
Description 给出两个01序列\(A\)和\(B\) 要求回答\(q\)个询问每次询问\(A\)和\(B\)中两个长度为\(len\)的子串的哈明距离 哈明距离的值即有多少个位置不相等 ...
- 【51Nod1847】奇怪的数学题
记\(f(x)=\)\(x\)的次大因数,那么\(sgcd(i,j)=f(gcd(i,j))\). 下面来推式子: \[ \begin{aligned} \sum_{i=1}^n\sum_{j=1 ...