List介绍
List是Java中比较常用的集合类型之一,它是一个接口,继承于Collection接口,其中实现类中常见的有ArrayList、LinkedList、Vector等子类。
List中元素可以重复,并且是有序的。(这里的有序指的是按照放入的顺序进行存储。)
1、ArrayList底层是数组实现的,是一种可以动态增长和缩减的索引序列。数组和数组列表中有一个重大的缺陷:从数组的中间位置删除一个元素要付出很大的代价,因为在数组中处于被删除元素之后的所有元素都要向数组前端移动,在数组中间插入元素也是如此,所以数组在删除和插入的操作上效率低。
实现:
public void invoke(){
//初始化
List<String> list=new ArrayList<>();
//赋值
list.add("one");
list.add("two");
list.add("one");
list.add("one");
list.add("abc");
Log.d("TestList","size===="+list.size());
//遍历集合
for (int i = 0; i < list.size(); i++) {
String str=list.get(i);
Log.d("TestList",str);
}
Log.d("TestList","------------remove------------");
//for循环删除元素
for (int i = 0; i < list.size(); i++) {
String str=list.get(i);
if(str.equals("one")){
list.remove(i);
}
Log.d("TestList",str);
}
}
TestList: size====5
TestList: [one, two, one, one, abc]
TestList: ----for循环remove----
TestList: [two, one, abc]
通过ArrayList的remove方法进行删除元素打印出的结果中还存在one,出现删除的元素并没有完全被删除的情况。
Log.d("TestList","----遍历器删除----");
for (String s : list) {
if(s.equals("one")){
list.remove(s);
}
}
Log.d("TestList",list.toString());
通过遍历器删除,报以下异常
Caused by: java.util.ConcurrentModificationException
Log.d("TestList","----Iterator----");
//迭代器删除元素
Iterator iterator=list.iterator();
while (iterator.hasNext()) {
if(iterator.next().equals("one")){
iterator.remove();
}
}
Log.d("TestList",list.toString());
TestList: ----Iterator----
TestList: [two, abc]
通过迭代器判断进行删除元素,打印结果正常。
综上所述,在对ArrayList进行遍历删除时,建议使用迭代器Iterator进行遍历删除。(面试中被问到的几率还是不小的)
2、LinkdeList底层是链表实现的。是一种可以在任何位置进行高效的插入和删除的有序序列。链表将每个对象存放在独立的结点中,每个结点还存放着序列中下一个结点的引用。所以在链表中删除一个元素是一个很轻松的操作,只需要对被删除元素附近的结点更新一下即可。在Java程序语言中,所有链表实际上都是双向链接的(doubly linked),每个结点还存放着指向前驱结点的引用。
实现:
public void invoke(){
List<String> list=new LinkedList<>();
list.add("aaa");
list.add("abc");
list.add("aa");
Log.d("Testlinked",list.toString()+",size===="+list.size());
}
Testlinked: [aaa, abc, aa],size====5
Log.d("Testlinked","-----Iterator-----");
Iterator<String> iterator=list.iterator();
String first=iterator.next();
String second=iterator.next();
iterator.remove();
Log.d("Testlinked",list.toString());
Testlinked: -----Iterator-----
Testlinked: [aaa, aa]
3、Vector和ArrayList一样底层都是数据实现的,Vector是线程安全的,ArrayList、LinkedList都是线程不安全的,即在多线程下修改数据可能会造成数据错乱,重复增删等问题。Vector中的很多重要方法都是用synchronized实现同步,保证线程安全。在多线程下如果要保证线程安全,那么使用Vector比较好,但是在保证线程安全的同时效率也会下降。如果你的程序不涉及到线程安全问题,那么使用ArrayList是更好的选择(因为Vector使用synchronized,必然会影响效率)。
Vector和ArrayList二者之间还有一个区别,就是扩容策略不一样。在List被第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。
综上所述,在需要频繁读取集合中的元素时,使用ArrayList效率较高,而在插入和删除操作较多时,使用LinkedList效率较高。使用Vector可以多线程下保证修改数据线程安全(当然,你也可以使用ArrayList并自己实现同步)。
Set介绍
Set也是ava中比较常用的集合类型之一,它是一个接口,和List一样继承于Collection接口,其中实现类中常见的有HashSet、TreeSet等子类。Set是没有重复元素的集合,是无序的。
1、HashSet实现了基于散列表的集。可以用add方法添加元素。可以快速的查看某个元素是否出现在集中,只在某个桶中查找元素,而不必查看集合中的所有元素。HashSet不能存储重复的值,如果key已存在内容会被覆盖。允许null值,非线程安全。
实现:
public void invoke(){
Set<String> set=new HashSet<>();
set.add("abc");
set.add("ab");
set.add("ccc");
Log.d("TestSet",set.toString());
//存储null值
set.add(null);
Log.d("TestSet",set.toString());
set.add("oi");
Log.d("TestSet",set.toString());
//存储相同的值
set.add("oi");
Log.d("TestSet",set.toString());
//遍历
Iterator<String> iterator=set.iterator();
while (iterator.hasNext()) {
String str=iterator.next();
Log.d("TestSet",str+"");
}
}
TestSet: [abc, ab, ccc]
TestSet: [null, abc, ab, ccc]
TestSet: [null, abc, oi, ab, ccc]
TestSet: [null, abc, oi, ab, ccc]
2、TreeSet类与散列集十分相似,不过,它比散列集有所改进。树集是一个有序的集合。可以以任意顺序将元素插入到集合中。在对集合进行遍历时,每个值会自动的按照排序后的顺序呈现。
实现:
public void invoke(){
Set<Integer> set=new TreeSet<>();
set.add(777);
set.add(1);
set.add(23);
set.add(98);
set.add(33);
set.add(66);
Log.d("TestTree",set.toString());
}
TestTree: [1, 23, 33, 66, 98, 777]
Map介绍
Map是以键值对形式存储数据,不能存储重复的元素。有HashMap、LinkedHashMap、TreeMap等子类。
1、HashMap是哈希表结构,不保证存取顺序,允许null键或者null值,效率较高。实现了Map接口。
public void invoke(){
Map map=new HashMap();
map.put("aaa","aaa");
Log.d("TestMap",map.toString());
map.put(null,null);
Log.d("TestMap",map.toString());
Log.d("TestMap","aaa==="+map.get("aaa"));
Log.d("TestMap","null==="+map.get(null));
}
TestMap: {aaa=aaa}
TestMap: {null=null, aaa=aaa}
TestMap: aaa===aaa
TestMap: null===null
public void invoke(){
Map map=new HashMap();
map.put("aaa","aaa");
map.put("a","aaa");
map.put("aa","aaa");
Log.d("TestMap",map.toString());
//遍历Map
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
Log.d("TestMap", "Key = " + key + ", Value = " + value);
}
}
TestMap: {aa=aaa, a=aaa, aaa=aaa}
TestMap: Key = aa, Value = aaa
TestMap: Key = a, Value = aaa
TestMap: Key = aaa, Value = aaa
2、LinkedHashMap带双向链表的哈希表结构,保持存取顺序,允许null键和null值,非线程安全,效率较高。
public void invoke(){
Map maplink=new LinkedHashMap();
maplink.put("aaa","123456789");
maplink.put("aaa","123456789");
maplink.put("aaa","123456789");
maplink.put("aaa","123456789");
Log.d("TestMap",maplink.toString());
}
TestMap: {aaa=123456789}
3、TreeMap平衡排序二叉树(红黑树)结构,按自然排序或比较器存入元素以保证元素顺序。非线程安全。
这篇文章主要巩固一下几种集合类相关的基础知识,也加深一下印象,如果文章中有错误有问题,欢迎指出,以后会日益完善。