集合(二)Collection集合Set
一、无序列表Set: 是一个散列的集合,数据会按照散列值存储的,如两个hello的散列值相同,会存储在同一个地址中,所以看到的就是只有一个hello在集合中了。
1、Set集合有两个主要的实现子类:Hashset和Treeset。hashset是去重复,而Treeset需要实现compareble接口来排序(比较其实是一种变向的去重复,一旦两个对象比较的元素相同,这两个对象只会存一个进去)。
2、Set的特征:
不会出现重复的元素(按照equals 和hashCode 的规则比较是否重复)
Set属于Collection的子接口,拥有Collection的所有的方法;
Set 是散列存储没有位置编号,没有按照编号进行操作的方法。
注意Set<T>如果这个T没有正确重写equals和hashCode方法,会存入重复值。而List<T>即使T正确重写了equals和hsahCode方法,也会存入重复值。
二、Hashset:无序,不排序。
1、底层原理:HashSet底层是哈希表结构的。哈希表:
(1)JDK8之前,底层采用数组+链表实现。
HashSet<String> haset1 = new HashSet<>();
创建一个空的hashSet时,底层创建一个默认长度16,默认加载因子0.75的数组,数组名table?
(2)JDK8以后,底层进行了优化。由数组+链表+红黑树实现:如果链表长度很长时,新存入的元素,需要通过equals比较的次数就越多,性能就会降低,即链表长度越长,添加元素时,效率越低,jdk1.8对此进行了优化,当链表长度为8时,再次添加元素自动转换成红黑树 ,当链表长度小于6时,自动转为链表。好处 equals比较次数减少,小了往左边比较,大了往右边比较。
2、线程安全问题:
线程不安全。
public static void main(String[] args) {
Set<String> hashSet = new HashSet<>();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
//向集合中添加内容
hashSet.add(UUID.randomUUID().toString().substring(0, 8));
//从集合中获取内容
System.out.println(hashSet);
}, String.valueOf(i)).start();
}
}
/*
Exception in thread "0" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445)
at java.util.HashMap$KeyIterator.next(HashMap.java:1469)
at java.util.AbstractCollection.toString(AbstractCollection.java:461)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at HashSetDemo.lambda$main$0(HashSetDemo.java:13)
at java.lang.Thread.run(Thread.java:748)
*/
}
HashSet线程不安全解决方案:?
三、Treeset:
1、底层原理:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!