前言
泛型+反射+注释+XML = 框架
区别数组,但是长度可变;
ArrayList: 遍历,查找 快
LinkedList: 插入,删除 快
TreeMap: 有序的进,有序的出
接口类型 | 数据内容 | 顺序 |
---|---|---|
List接口 | 可重复 | 有序 |
Set接口 | 不可重复 | 无序 |
Map接口 | 键值对 | 无序 |
Collection和Collections
java.util
在集合框架中,分为两种API :
1、装载数据的集合类
2、操作集合的工具类
集合Collection
集合( Collection )接口位于Set接口和List接口的最顶层,是Set接口和List接口的父接口。定义了Collection对象共有的一些基本方法,这些方法分为基本操作、批量操作和数组操作。Iterator接口是一 种用于遍历集合的接口。所谓遍历,是指从集合中取出每一个元素的过程。
E - 此集合中元素的类型
方法:
- boolean add(E e) 确保此集合包含指定的元素(可选操作)。
- boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合(可选操作)。
- void clear() 从此集合中删除所有元素(可选操作)。
- boolean contains(Object o) 如果此集合包含指定的元素,则返回 true 。 ——containsAll(Collection<?> c)
- boolean equals(Object o) 将指定的对象与此集合进行比较以获得相等性。
- boolean isEmpty() 如果此集合不包含元素,则返回 true 。
- Iterator iterator() 返回此集合中的元素的迭代器。
- boolean remove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
- boolean removeAll(Collection<?> c) 删除指定集合中包含的所有此集合的元素(可选操作)。
- int size() 返回此集合中的元素数。
- Object[] toArray() 返回一个包含此集合中所有元素的数组。
Collections 集合工具类(包含方法均为static)
(参考API)
方法:sort(), reverse(), shuffle()
public class TestTool {
public static void main(String[] args) {
List<Integer> list = new ArrayList();
list = new LinkedList<>(list);
list.add(11);
list.add(1);
list.add(111);
list.add(2);
//排序
Collections.sort(list);
for (Integer integer : list) {
System.out.println(integer);
}//1 2 11 111
System.out.println("-----------------");
Collections.reverse(list);
for (Integer integer : list) {
System.out.println(integer);
}//111 11 2 1
System.out.println("-----------------");
Collections.shuffle(list);//乱序
for (Integer integer : list) {
System.out.println(integer);
} //11 1 2 111
System.out.println("-----------------");
Object[] arry = list.toArray();
//排序
Arrays.sort(arry);
for (Object integer : arry) {
System.out.println(integer);
} // 1 2 11 111
}
}
Arrays数组工具类
(参考API)
static void sort(byte[] a) :按照数字顺序排列指定的数组。
1 List
List接口实现类的选择:
●ArrayList : 使用最广泛,集合元素增加或删除操作不频繁时使用,最适合查询。
●LinkedList : 当需要在集合的中间位置,频繁增加或删除元素时使用。
●Vector : 与ArrayList类似,但Vector是线程安全的,所以性能要低于ArrayList。
●LinkedList > ArrayList > Vector
List接口是继承Collection接口,所以Collection集合中有的方法,List集合也继承过来;此接口的用户可以对列表中每个元素的插入位置进行精确地控制;列表通常有序(存储和取出的元素一致),允许重复的元素;
方法:
- void add(int index, E element):
在指定位置插入元素,后面的元素都往后移一个元素; - boolean addAll(int index, Collection<? extends E> c):
当插入的集合c没有元素,那么就返回false,如果集合c有元素,插入成功,那么就返回true; - E get(int index):返回list集合中指定索引位置的元素;
- int indexOf(Object o):
返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1; - ListIterator listIterator():
返回此列表元素的列表迭代器(按适当顺序); - ListIterator listIterator(int index):
从指定位置开始,返回此列表元素的列表迭代器(按适当顺序); - E remove(int index):
删除指定索引的对象; - E set(int index, E element):
在索引为index位置的元素更改为element元素 - List subList(int fromIndex, int toIndex):
返回从索引fromIndex到toIndex的元素集合,包左不包右。
List list = new ArrayList();
list.add("demo1");
list.add("demo2");
list.add("demo3");
// 遍历:
Iterator i = list.iterator();
while(i.hasNext()) {
String s = (String) i.next();
System.out.println(s);
}
1.1 ArrayList
- ArrayList实现了可变大小的数组。
- 它允许所有元素,包括null。
- 和LinkedList一样,ArrayList也是非同步的(unsynchronized)(异步)。线程不安全
- size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
- 每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
- 支持随机访问。当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
1.1.1 构造函数
public ArrayList()
public ArrayList(int initialCapacity)
public ArrayList(Collection<? extends E> c):按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。如果集合长度为0则为{}
/**
* Constructs an empty list with an initial capacity of ten.
* 构造一个空的集合初始容量是10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
1.1.2 常用方法
add()
扩容grow()
public E remove(int index)
get (因为底层使用数组来实现,所以 底层直接通过[index]的方式获取和设置值)
set()
equals()
public ListIterator listIterator(int index)
E get(int index)
List subList(int fromIndex, int toIndex)
1.1.3 总结
- 底层数组
- 有序,可重复
- 速度快,增删慢(数组的移位)
- 线程不安全
- 容量不够时,扩容后的容量 = 当前容量*1.5+1;、
import java.util.ArrayList;
import java.util.Iterator;
import day3.exciting.Person;
public class TestArrayList {
public static void main(String[] args) {
ArrayList list = new ArrayList();
System.out.println(list.size()); // 0
list.add(2);
list.add(false);
list.add(1);
list.add("abc");
list.add(new Object());
list.add(true);
list.add(true);
Integer j = 1;
list.remove(j); // 基本数据类型的话,就是下标
list.set(1, new Person());
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
/*
* 2
day3.exciting.Person@15db9742
abc
java.lang.Object@6d06d69c
true
true
*/
System.out.println("--------------------------");
// list.clear();
System.out.println(list.get(2)); // abc
//foreach
for (Object object : list) {
System.out.println(object);
}
System.out.println("--------------------------");
//迭代 先获得迭代器
Iterator it = list.iterator();
while(it.hasNext()){//有没有下一个元素
System.out.println(it.next());//下一个元素
}
System.out.println("------------不打印的原因 迭代结束--------------");
while(it.hasNext()){//有没有下一个元素
System.out.println(it.next());//下一个元素
}
}
}
1.2 LinkedList
LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(…));
public static void main(String[] args) {
// 表头和表位进行扩展 大的数据量排序 LinkedList
LinkedList list = new LinkedList();
list.add("1");// linkLast(e);
list.addFirst("2");// linkFirst(e);
list.addLast("3");// linkLast(e);
list.offerFirst("4") ;//addFirst
list.offerLast("5");
list.add(2, true);
//void add(int index, E element)
//在此列表中的指定位置插入指定的元素
}
1.3 Vector
可实现自动增长的对象数组。
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
1.3.1 构造方法
- public vector() :构造一个空向量,使其内部数据数组的大小为 10 ,标准容量增量为零(自动对向量进行管理)
- public vector(int initialcapacity):构造具有指定初始容量并且其容量增量等于零的空向量
- public vector(int initialcapacity,int capacityIncrement) :构造具有指定的初始容量和容量增量的空向量
1.3.2 方法
(参考API)
常用:
- boolean add(E e)
将指定的元素追加到此Vector的末尾 - void add(int index, E element)
在此Vector中的指定位置插入指定的元素 - void addElement(E obj)
将指定的组件添加到此向量的末尾,将其大小增加1。 - boolean addAll(int index, Collection<? extends E> c)
将指定集合中的所有元素插入到此向量中的指定位置 - int capacity()返回此向量的当前容量; int size()向量中的组件数
- boolean contains(Object obj)
向量包含指定元素返回true - E get(int index)
返回此向量中指定位置的元素 - int indexOf(Object o, int index)
返回此向量中指定元素的第一次出现的索引,从 index向前 index ,如果未找到该元素,则返回-1 - E remove(int index)
删除此向量中指定位置的元素 - public final int indexOf(Object obj)
从向量头开始搜索obj,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1
1.4 ArrayList和LinkedList以及Vector的区别
注意点:
- 如果是jdk6的话,采用Array.of()方法来生成一个新的数组,如果是jdk5.0的话,使用的是 System.arraycopy方法(将数组拷贝)
- List list = new ArrayList();时,底层会生成一个长度为10的数组来存放对象,如果预先知道list 会存放多少个对象的话,最好通过new ArrayList(int length)的方式先确定数组的最小长度,如new ArrayList(50),这样能提高底层的效率。
- 对于ArrayList与Vector来说,底层都是采用数组方式来实现的(该数组是一个Object类型的数组)。此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差。
- 对于ArrayList,所有方法都不是同步的,对于Vector,大部分是public的方法都是同步的。
- LinkedList底层是由双向循环链表实现的,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。LinkedList查找速度非常慢,增加和删除操作非常快(本质上是由双向循环链表的特点来决定的)。
- 对于ArrayList,查找速度非常快,增加和删除操作非常慢。(本质上是由数组的特点来决定的)
1.存储结构
ArrayList和Vector是按照顺序将元素存储(从下标为0开始),删除元素时,删除操作完成后,需要使部分元素移位,默认的初始容量都是10.
ArrayList和Vector是基于数组实现的,LinkedList是基于双向链表实现的(含有头结点)。
2.线程安全性
ArrayList不具有有线程安全性,在单线程的环境中,LinkedList也是线程不安全的,如果在并发环境下使用它们,可以用Collections类中的静态方法synchronizedList()对ArrayList和LinkedList进行调用即可。
Vector实现线程安全的,即它大部分的方法都包含关键字synchronized,但是Vector的效率没有ArraykList和LinkedList高。
3.扩容机制
从内部实现机制来讲,ArrayList和Vector都是使用Object的数组形式来存储的,当向这两种类型中增加元素的时候,若容量不够,需要进行扩容。ArrayList扩容后的容量是之前的1.5倍,然后把之前的数据拷贝到新建的数组中去。而Vector默认情况下扩容后的容量是之前的2倍。
Vector可以设置容量增量,而ArrayList不可以。在Vector中,有capacityIncrement:当大小大于其容量时,容量自动增加的量。如果在创建Vector时,指定了capacityIncrement的大小,则Vector中动态数组容量需要增加时,如果容量的增量大于0,则增加的是大小是capacityIncrement,如果增量小于0,则增大为之前的2倍。
在这里需要说一下可变长度数组的原理:当元素个数超过数组的长度时,会产生一个新的数组,将原数组的数据复制到新数组,再将新的元素添加到新数组中。
4.增删改查的效率
ArrayList和Vector中,从指定的位置检索一个对象,或在集合的末尾插入、删除一个元素的时间是一样的,时间复杂度都是O(1)。但是如果在其他位置增加或者删除元素花费的时间是O(n),LinkedList中,在插入、删除任何位置的元素所花费的时间都是一样的,时间复杂度都为O(1),但是他在检索一个元素的时间复杂度为O(n).
所以如果只是查找特定位置的元素或只在集合的末端增加移动元素,那么使用ArrayList或Vector都是一样的。如果是在指定位置的插入、删除元素,最好选择LinkedList
区别的原文链接:https://blog.csdn.net/kuangsonghan/article/details/79861170
2 Set
Set接口继承了Collection接口。Set集合不包含重复的元素(元素加入set中,重复的元素会自动移除),每个元素必须是唯一,这是使用Set的主要原因。
有三种常见的Set实现——HashSet, TreeSet和LinkedHashSet。如果你需要一个访问快速的Set,你应该使用HashSet;当你需要一个排序的Set,你应该使用TreeSet;当你需要记录下插入时的顺序时,你应该使用LinedHashSet。
1.1 HashSet
HashSet实现了Set接口,不重复无序,可以有一个null元素;
将对象存储在HashSet之前,要确保重写hashCode()方法和equals()方法,这样才能比较对象的值是否相等,确保集合中没有储存相同的对象。如果不重写上述两个方法,那么将使用下面方法默认实现:
public boolean add(Object obj)方法用在Set添加元素时,如果元素值重复时返回 “false”,如果添加成功则返回"true"
boolean add() 判定标准:hashCode值相同 和equals时true :
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class TestSet {
public static void main(String[] args) {
HashSet set = new HashSet();
//判断 对象是否相同 hashCode 和equals
set.add(new Student("韩梅梅"));
set.add(new Student("李磊"));
set.add("b");
set.add(1);
set.add(2);
set.add(2);
set.add(new Student("韩梅梅"));
System.out.println(set.size()); // 6
//两种
for (Object object : set) {
System.out.println(object);
}
/**
* Student [name=韩梅梅, className=null, score=0]
1
b
2
Student [name=韩梅梅, className=null, score=0]
Student [name=李磊, className=null, score=0]
*/
Iterator iterator = set.iterator(); //迭代
List list = new ArrayList();
list.add(1);
list.add(true);
list.add("abc");
// set.addAll(list);//把集合里面元素一个一个放置集合中 //8
set.add(list);//把集合作为一个元素放入集合中
System.out.println(set.size()); // 7
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
} // 输出顺序不确定
}
}
1.2 TreeSet
底层的数据结构是红黑树(一种自平衡二叉查找树)
有序,无重复集合。不可以有Null元素,根据元素的自然顺序进行排序。
作用:提供有序Set集合,因此支持add(),remove(),get()
继承AbstractSet抽象类,可以被实例化;一种基于TreeMap的NavigableSet实现。
TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。这取决于使用的构造方法。
TreeSet的性能比HashSet差,但是在需要排序的时候可以用TreeSet,因为他是自然排序,也就是升序。
不支持快速随即遍历,只能通过迭代器进行遍历。
1.3 LinkedHashSet
底层数据结构由哈希表和链表组成。
LinkedHashSet介于HashSet和TreeSet之间。它也是一个hash表,但是同时维护了一个双链表来记录插入的顺序。
1.4 .HashSet和TreeSet以及LinkedHashSet区别
HashSet是采用hash表来实现的。
TreeSet是采用树结构实现(红黑树算法)。
LinkedHashSet介于HashSet和TreeSet之间。它也是一个hash表,但是同时维护了一个双链表来记录插入的顺序。
无排序要求可以选用HashSet;如果想取出元素的顺序和放入元素的顺序相同,那么可以选用LinkedHashSet。如果想插入、删除立即排序或者按照一定规则排序可以选用TreeSet。
HashSet | TreeSet | LinkedHashSet |
---|---|---|
不重复(可以有一个null元素),无序 | 不重复(不可以有null元素),有序 | 不重复(可以有一个null元素),无序 |
确保唯一性:hashCode(),equals() | 底层的数据结构是红黑树(一种自平衡二叉查找树) | 链表保证了元素的有序即存储和取出一致,哈希表保证了元素的唯一性 |
add()、remove()以及contains()等方法都是复杂度为O(1)的方法 | 添加、删除操作时间复杂度O(log(n));还提供了一些方法来处理排序的set,如first(), last(), headSet(), tailSet() | 添加、删除操作时间复杂度O(1) |
非线程安全 | 非线程安全 | 非线程安全 |
HashSet和TreeSet区别,参考一下别人的:
https://www.cnblogs.com/williamjie/p/9099038.html
3 Map
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
Map接口有两个基本的实现TreeMap和HashMap。
interface Map<K,V>
K - 此映射所维护的键的类型
V - 映射值的类型
1.map存储键值对,每个键(key)都有一个对应的值(value)。键不可以重复(唯一性),值可以重复。
2.Map和Collection在集合框架中属并列存在,Map存储元素使用put方法,Collection使用add方法;
3.Map一次存一对元素, Collection 一次存一个,也就是Collection是单列集合, Map 是双列集合;
4.Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
遍历Map方式:
第一种方式: 使用keySet:
将Map转成Set集合(keySet()),通过Set的迭代器取出Set集合中的每一个元素(Iterator)就是Map集合中的所有的键,再通过get方法获取键对应的值。
第二种方式: 通过values 获取所有值,不能获取到key对象(Collection coll = map.values(); )
第三种方式: Map.Entry
public static interface Map.Entry<K,V>
通过Map中的entrySet()方法获取存放Map.Entry<K,V>对象的Set集合。
Set<Map.Entry<K,V>> entrySet()
面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class TestMap {
public static void main(String[] args) {
//创建集合对象
Map<String,Integer> map = new HashMap();
map.put("A", 1);
map.put("B", 1);
map.put("C", 11);
map.put("A", 12); // 覆盖
//循环出键值对
for(Object obj : map.entrySet()){ //Set key = value
System.out.println(obj);
}
/*
A=12
B=1
C=11
*/
//获得所有的键
System.out.println("--------------------");
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key + ":" + map.get(key));// 用键获得值
}
//返回所有
Collection coll = map.values();
map.remove("A") ;//移除的是键值对
System.out.println(coll); // 获取值 [1, 11]
System.out.println(map); // {B=1, C=11}
}
}
3.1 HashMap
底层是哈希表数据结构,所以无序,线程是不同步的,要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许出现重复的键(Key)。TreeMap保存了对象的排列次序,而HashMap不能。HashMap可以有空的键值对(Key(null)-Value(null))
HashMap是非线程安全的(非Synchronize),要想实现线程安全,那么需要调用collections类的静态方法synchronizeMap()实现。
常用方法:
public Object put(Object Key,Object value)方法用来将元素添加到map中。
contains(),get()
import java.util.HashMap;
import java.util.Map;
public class Test {
public static Map<Integer, Integer> countArrNum(Object[] obj) {
Map<Integer, Integer> map = new HashMap();
// 循环元素
for(Object key : obj) {
// 判断这个元素在Map的key中是否存在
if(!map.containsKey(key)) {
map.put((Integer) key, 1); // 第一次出现
} else {
// 总次数 = 原来的次数+1 : map.get(key) + 1
map.put((Integer) key, map.get(key) + 1);
}
}
return map;
}
public static void main(String[] args) {
Integer[] arr = {1,2,3,4,1,2,4,3,4,5};
Map<Integer, Integer> map = countArrNum(arr);
System.out.println(map);
for (Integer key : map.keySet()) {
System.out.println(key + "出现次数:" + map.get(key));
}
}
}
/*
{1=2, 2=2, 3=2, 4=3, 5=1}
1出现次数:2
2出现次数:2
3出现次数:2
4出现次数:3
5出现次数:1
*/
3.2 HashMap,TreeMap,HashTable的区别
HashMap | TreeMap | HashTable | LinkedHashMap | ConcurrentHashMap |
---|---|---|---|---|
底层是哈希表数据结构 | 底层是二叉树数据结构 | 底层是哈希表数据结构 | 该子类基于哈希表又融入了链表 | |
线程不同步,线程不安全 | 线程不同步 | 线程同步,线程安全 | 线程安全(在多线程和并发环境中,通常作为Map的主要实现) | |
可以存入null键,null值 | 不可以存入null键,null值 | |||
可以对map集合中的键进行排序 | 效率较低,被HashMap 替代 | 可以Map集合进行增删提高效率 | 通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍 | |
保证键的唯一性,需要覆盖hashCode方法,和equals方法 | 使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性 | |||
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂 | 初始size为11,扩容:newsize = olesize*2+1 |
面试问答题,HashMap、Hashtable、ConcurrentHashMap的原理与区别,参考一下别人的:
https://www.cnblogs.com/heyonggang/p/9112731.html
常见方法:
- 添加:
- V put(K key, V value) (可以相同的key值,但是添加的value值会覆
盖前面的,返回值是前一个,如果没有就返回null) - putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关
系复制到此映射中(可选操作)。
- 删除
- remove() 删除关联对象,指定key对象
- clear() 清空集合对象
- 获取
- value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返回的是null。
- 判断:
- boolean isEmpty() 长度为0返回true否则false
- boolean containsKey(Object key) 判断集合中是否包含指定的key
- boolean containsValue(Object value) 判断集合中是否包含指定的value
- 长度:int size()
4 其他
4.1 了解泛型
泛型:广泛的引用数据类型,出现于1.5
当不知道想采用的数据类型可以定义为泛型,泛型默认为Object
类<>
方法:传入数据的时候确定数据的类型
在集合中——定义泛型:定义集合的数据类型
public class TestAll<T,W> {//泛型 + 反射 + 注解 + XML + 设计模式 = 框架 JDBC
T other;
// 当不知道返回的类型 具体是什么的时候可以定义为泛型
public<K> K update(K k){
System.out.println("k--修改");
if(k instanceof String){
return (K) ((String) k).concat("abc");//final
}
if(k instanceof Student){
((Student) k).setName("真好");
}
return k;
}
public static void main(String[] args) {
TestAll<String,Object> ta=new TestAll<>();
ta.other="abc";
System.out.println(ta.update("你好"));
System.out.println(ta.update(new Student("韩梅梅","201",99)));
//TestAll<Student> ta2 = new TestAll<>();
//ta2.other=new Student();
/*
k--修改
你好abc
k--修改
Student [name=真好, className=201, score=99]
*/
}
}
4.2 List和Set区别
Collection是最基本的集合接口,声明了适用于JAVA集合的通用方法,list和set都继承自collection接口。Java中的集合包括三大类,它们是Set(集)、List(列表)和Map(映射),它们都处于java.util包中,Set、List和Map都是接口,它们有各自的实现类。Set的实现类主要有HashSet、LinkedHashSet和TreeSet,List的实现类主要有ArrayList、LinkedList和Vector。
区别:
1、List,Set都是继承自Collection接口
2、List特点:元素有放入顺序(输出顺序为插入顺序),元素可重复,可以插入多个null元素 ,
Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉,只允许一个null元素
(元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
3、Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
4.3 HashSet和HashMap的区别
HashMap | HashSet |
---|---|
实现了Map接口 | 实现了Set接口 |
存储键值对 | 仅存储对象 |
调用put() 向map中添加元素 | 调用add()向set中添加元素 |
HashMap使用键(key)计算Hashcode | HashSet使用成员对象来计算Hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false |
HashMap相对于HashSet较快,因为它是使用唯一的键获取对象 | HashSet较HashMap来说比较慢 |
4.4 HashMap与ConcurrentHashMap的区别
上面所说他们之间的第一个重要的区别就是ConcurrentHashMap是线程安全的和在并发环境下不需要加额外的同步。虽然它不像Hashtable那样需要同样的同步等级(全表锁),但也有很多实际的用途。
- 可以使用Collections.synchronizedMap(HashMap)来包装HashMap作为同步容器,这时它的作用几乎与Hashtable一样,当每次对Map做修改操作的时候都会锁住这个Map对象,ConcurrentHashMap会基于并发的等级来划分整个Map来达到线程安全,它只会锁操作的那一段数据而不是整个Map都上锁。
- ConcurrentHashMap有很好的扩展性,在多线程环境下性能方面比做了同步的HashMap要好,但是在单线程环境下,HashMap会比ConcurrentHashMap好一点。
以上两者的区别,在于线程安全、扩展性、同步之间的区别。如果是用于缓存的话,ConcurrentHashMap是一个更好的选择,在Java应用中会经常用到,并且在读操作线程数多于写操作线程数的情况下更胜一筹。