一.简介
Collection是最基本的集合/容器接口,一个Collection代表一组Object,即Collection的元素。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
图解
即:
Collection主要子接口对象
List接口 元素可重复。
Set接口 元素不可重复。
Map接口 没有继承Collection接口,Map提供key到value的映射。
下面对List,Map,Set。一一讲解。
二.List接口详解
1.List接口描述
List是有序,可重复的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,也就是说它是有顺序的,类似于Java的数组。和Set不同,List允许有相同的元素。J2SDK所提供的List容器类有ArrayList、LinkedList等。
2.List接口的实现类之ArrayList
<1> ArrayList描述
ArrayList其实就相当于顺式存储,它包装了一个数组 Object[],当实例化一个ArrayList时,一个数组也被实例化,当向ArrayList中添加对象时,数组的大小也相应的改变。
<2> ArrayList特点
(1) 快速随即访问,你可以随即访问每个元素而不用考虑性能问题,通过调用get(i)方法来访问下标为i的数组元素。
(2) 向其中添加对象速度慢,当你创建数组时并不能确定其容量,所以当改变这个数组时就必须在内存中做很多事情。
(3) 操作其中对象的速度慢,当你要向数组中任意两个元素中间添加对象时,数组需要移动所有后面的对象。
<3> ArrayList使用demo
代码
package com.example.mytest;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
List<String> list = new ArrayList<String>();
list.add(null);
list.add("bbbb");
list.add("bbbb");
list.add("bbbb");
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
list.add("dddd");
list.add("dddd");
list.add("dddd");
list.add(null);
Iterator<String> i = list.iterator();
while (i.hasNext()) {
Log.i("TAG", "Iterator遍历----:" + i.next());
}
Log.i("TAG", "*****************************************");
for (int m = 0; m < list.size(); m++) {
Log.i("TAG", "for循环----:" + list.get(m));
}
Log.i("TAG", "*****************************************");
Log.i("TAG", "list长度----:" + list.size());
}
}
结果
I/TAG: Iterator遍历----:null
I/TAG: Iterator遍历----:bbbb
I/TAG: Iterator遍历----:bbbb
I/TAG: Iterator遍历----:aaaa
I/TAG: Iterator遍历----:bbbb
I/TAG: Iterator遍历----:cccc
I/TAG: Iterator遍历----:dddd
I/TAG: Iterator遍历----:dddd
I/TAG: Iterator遍历----:null
I/TAG: *****************************************
I/TAG: for循环----:null
I/TAG: for循环----:bbbb
I/TAG: for循环----:bbbb
I/TAG: for循环----:aaaa
I/TAG: for循环----:bbbb
I/TAG: for循环----:cccc
I/TAG: for循环----:dddd
I/TAG: for循环----:dddd
I/TAG: for循环----:null
I/TAG: *****************************************
I/TAG: list长度----:11
也就是说ArrayList 有序(插入和输出顺序一致) 元素可重复 元素可为空 。
3.List接口的实现类之LinkedList
<1> LinkedList描述
LinkedList相当于链式存储,它是通过节点直接彼此连接来实现的。每一个节点都包含前一个节点的引用,后一个节点的引用和节点存储的值。当一个新节点插入时,只需要修改其中保持先后关系的节点的引用即可,当删除记录时也一样。
<2> LinkedList有特点
(1) 操作其中对象的速度快,只需要改变连接,新的节点可以在内存中的任何地方。
(2) 不能随即访问,虽然存在get()方法,但是这个方法是通过遍历接点来定位的,所以速度慢。
<3> Linkedlist使用demo
代码
package com.example.mytest;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initLinkedList();
}
public void initLinkedList() {
List<String> list = new LinkedList<String>();
list.add(null);
list.add("bbbb");
list.add("bbbb");
list.add("bbbb");
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
list.add("dddd");
list.add("dddd");
list.add("dddd");
list.add(null);
Iterator<String> i = list.iterator();
while (i.hasNext()) {
Log.i("TAG", "Iterator遍历----:" + i.next());
}
Log.i("TAG", "*****************************************");
for (int m = 0; m < list.size(); m++) {
Log.i("TAG", "for循环----:" + list.get(m));
}
Log.i("TAG", "*****************************************");
Log.i("TAG", "list长度----:" + list.size());
}
}
结果
I/TAG: Iterator遍历----:null
I/TAG: Iterator遍历----:bbbb
I/TAG: Iterator遍历----:bbbb
I/TAG: Iterator遍历----:aaaa
I/TAG: Iterator遍历----:bbbb
I/TAG: Iterator遍历----:cccc
I/TAG: Iterator遍历----:dddd
I/TAG: Iterator遍历----:dddd
I/TAG: Iterator遍历----:null
I/TAG: *****************************************
I/TAG: for循环----:null
I/TAG: for循环----:bbbb
I/TAG: for循环----:bbbb
I/TAG: for循环----:aaaa
I/TAG: for循环----:bbbb
I/TAG: for循环----:cccc
I/TAG: for循环----:dddd
I/TAG: for循环----:dddd
I/TAG: for循环----:null
I/TAG: *****************************************
I/TAG: list长度----:11
也就是说LinkedList 有序(插入和输出顺序一致) 元素可重复 元素可为空 。
以上可以看出ArrayList和LinkedList用法完全一样,只是底层实现不一样。
三.Set接口详解
1.Set描述
Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。
2.Set接口实现类之HashSet
<1> HashSet描述
此类实现 Set接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
<2> HashSet使用demo
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.HashSet;
import java.util.Iterator;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
HashSet<String> hs = new HashSet<String>();
hs.add(null);
hs.add("ffff");
hs.add("aaaa");
hs.add("aaaa");
hs.add("bbbb");
hs.add("bbbb");
hs.add("cccc");
hs.add("cccc");
hs.add("dddd");
hs.add(null);
Iterator<String> i = hs.iterator();
while (i.hasNext()) {
Log.i("TAG", i.next() + "");
}
}
}
结果
I/TAG: null
I/TAG: aaaa
I/TAG: bbbb
I/TAG: cccc
I/TAG: dddd
I/TAG: ffff
也就是说HashSet 无序(插入和输出顺序不一致) 元素不可重复 元素可为空 。
3.Set接口实现类之TreeSet
<1> TreeSet描述
此类实现Set接口,由二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值。
<2> TreeSet使用demo
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Iterator;
import java.util.TreeSet;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
TreeSet<String> hs = new TreeSet<String>();
hs.add("ffff");
hs.add("aaaa");
hs.add("aaaa");
hs.add("bbbb");
hs.add("bbbb");
hs.add("cccc");
hs.add("cccc");
hs.add("dddd");
Iterator<String> i = hs.iterator();
while (i.hasNext()) {
Log.i("TAG", i.next() + "");
}
}
}
结果
I/TAG: aaaa
I/TAG: bbbb
I/TAG: cccc
I/TAG: dddd
I/TAG: ffff
也就是说TreeSet 无序(插入和输出顺序不一致) 元素不可重复 元素不可为空 。
以上可以看出HashSet和TreeSet用法几乎一样(TreeSet元素不可为空),只是底层实现不一样。
四.Map接口
1.Map描述
Map没有继承Collection接口,Map接口是提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。即是一一映射,Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。
2.Map接口实现类之HaspMap
<1> HaspMap描述
添加数据使用put(key, value),取出数据使用get(key),HashMap是允许null,即null value和null key。但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。
<2> HashMap使用demo
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
HashMap<String, String> map = new HashMap<String, String>();
HashMap<String, String> allmap = new HashMap<String, String>();
/**
* put("key","value")——>“key”“values”
*/
map.put("1", "张三");
map.put("2", "李四");
map.put("3", "王五");
map.put("4", "赵六");
/**
* putAll(map); ——>把一个map全部放到另一个map中
*/
allmap.putAll(map);
/**
* get ——>根据key获取相应的values
*/
String str = map.get("2");
String allstr = allmap.get("2");
Log.i("TAG", "get ——>根据key获取相应的values----str----:" + str);
Log.i("TAG", "get ——>根据key获取相应的values----allstr----:" + allstr);
Log.i("TAG", "********************************************************************");
/**
* size——>map长度
*/
int len = map.size();
int alllen = allmap.size();
Log.i("TAG", "size——>map长度----len----:" + len);
Log.i("TAG", "size——>map长度----alllen----:" + alllen);
Log.i("TAG", "*********************************************************************");
/**
* containsKey(“key”)——>map中是否包含相应的key
*/
boolean b1 = map.containsKey("2");
Log.i("TAG", "containsKey(“key”)——>map中是否包含相应的key----b1----:" + b1);
Log.i("TAG", "**********************************************************************");
/**
* containsValue(“values”)——>map中是否包含相应的values
*/
boolean b2 = map.containsValue("李四");
Log.i("TAG", "containsValue(“values”)——>map中是否包含相应的values----b2----:" + b2);
Log.i("TAG", "*********************************************************************");
/**
* isEmpty ——>map是否为空
*/
boolean b3 = map.isEmpty();
Log.i("TAG", "isEmpty ——>map是否为空----b3----:" + b3);
Log.i("TAG", "****************************************************************");
/**
* map迭代方法1 ——>keySet()
* keySet()把Map集合中的所有键都保存到一个Set类型的集合对象中返回。
*/
Set<String> keyset = map.keySet();
Iterator<String> i1 = keyset.iterator();
while (i1.hasNext()) {
String key = i1.next();
String value = map.get(key);
Log.i("TAG", "keySet迭代key----:" + key + "----value----:" + value);
}
Log.i("TAG", "******************************************************************");
/**
* map迭代方法2 ——>values()
* values()把所有的值存储到一个Collection集合中返回,Collection<V> values():获取集合中所有值的集合。
* 缺点: values方法只能返回所有 的值,没有键。
*/
Collection<String> valuecollection = map.values();
Iterator<String> i2 = valuecollection.iterator();
while (i2.hasNext()) {
String value = i2.next();
Log.i("TAG", "values迭代" + "value----:" + value);
}
Log.i("TAG", "********************************************************************");
/**
* map迭代方法3 ——>entrySet()
* entrySet()这种方法既能够获取键又能够获取值。
*/
Set<Map.Entry<String, String>> keyvalue = map.entrySet();
Iterator<Map.Entry<String, String>> i3 = keyvalue.iterator();
while (i3.hasNext()) {
Map.Entry<String, String> me = i3.next();
String key = me.getKey();
String value = me.getValue();
Log.i("TAG", "entrySet迭代key----:" + key + "----value----:" + value);
}
Log.i("TAG", "******************************************************************");
/**
* remove ——>通过key 删除对应的values
*/
map.remove("2");//通过key 删除对应的值
Set<Map.Entry<String, String>> keyvalues = map.entrySet();
Iterator<Map.Entry<String, String>> i3s = keyvalues.iterator();
while (i3s.hasNext()) {
Map.Entry<String, String> me = i3s.next();
String key = me.getKey();
String value = me.getValue();
Log.i("TAG", "通过key 删除对应的values后entrySet迭代key----:" + key + "----value----:" + value);
}
Log.i("TAG", "******************************************************************");
/**
* clear ——>清空map中所有元素
*/
map.clear();
Log.i("TAG", "清空map中所有元素后len----:" + map.size());
}
}
结果
I/TAG: get ——>根据key获取相应的values----str----:李四
I/TAG: get ——>根据key获取相应的values----allstr----:李四
I/TAG: ********************************************************************
I/TAG: size——>map长度----len----:4
I/TAG: size——>map长度----alllen----:4
I/TAG: *********************************************************************
I/TAG: containsKey(“key”)——>map中是否包含相应的key----b1----:true
I/TAG: **********************************************************************
I/TAG: containsValue(“values”)——>map中是否包含相应的values----b2----:true
I/TAG: *********************************************************************
I/TAG: isEmpty ——>map是否为空----b3----:false
I/TAG: ****************************************************************
I/TAG: keySet迭代key----:1----value----:张三
I/TAG: keySet迭代key----:2----value----:李四
I/TAG: keySet迭代key----:3----value----:王五
I/TAG: keySet迭代key----:4----value----:赵六
I/TAG: ******************************************************************
I/TAG: values迭代value----:张三
I/TAG: values迭代value----:李四
I/TAG: values迭代value----:王五
I/TAG: values迭代value----:赵六
I/TAG: ********************************************************************
I/TAG: entrySet迭代key----:1----value----:张三
I/TAG: entrySet迭代key----:2----value----:李四
I/TAG: entrySet迭代key----:3----value----:王五
I/TAG: entrySet迭代key----:4----value----:赵六
I/TAG: ******************************************************************
I/TAG: 通过key 删除对应的values后entrySet迭代key----:1----value----:张三
I/TAG: 通过key 删除对应的values后entrySet迭代key----:3----value----:王五
I/TAG: 通过key 删除对应的values后entrySet迭代key----:4----value----:赵六
I/TAG: ******************************************************************
I/TAG: 清空map中所有元素后len----:0
3.Map接口实现类之HashTable
<1> HashTable描述
HashTable是线程安全的一个Collection。
<2> HashTable使用demo
代码
package com.example.test;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initArrayList();
}
public void initArrayList() {
Hashtable<String, String> hashtable = new Hashtable<String, String>();
Hashtable<String, String> allhashtable = new Hashtable<String, String>();
/**
* put("key","value")——>“key”“values”
*/
hashtable.put("1", "张三1");
hashtable.put("2", "李四1");
hashtable.put("3", "王五1");
hashtable.put("4", "赵六1");
/**
* putAll(hashtable); ——>把一个hashtable全部放到另一个hashtable中
*/
allhashtable.putAll(hashtable);
/**
* get ——>根据key获取相应的values
*/
String str = hashtable.get("2");
String allstr = allhashtable.get("2");
Log.i("TAG", "get ——>根据key获取相应的values----str----:" + str);
Log.i("TAG", "get ——>根据key获取相应的values----allstr----:" + allstr);
Log.i("TAG", "*********************************************************************");
/**
* size——>hashtable长度
*/
int len = hashtable.size();
int alllen = allhashtable.size();
Log.i("TAG", "size——>hashtable长度----len----:" + len);
Log.i("TAG", "size——>hashtable长度----alllen----:" + alllen);
Log.i("TAG", "************************************************************************");
/**
* containsKey(“key”)——>map中是否包含相应的key
*/
boolean b1 = hashtable.containsKey("2");
Log.i("TAG", "containsKey(“key”)——>hashtable中是否包含相应的key----b1----:" + b1);
Log.i("TAG", "*******************************************************************");
/**
* containsValue(“values”)——>map中是否包含相应的values
*/
boolean b2 = hashtable.containsValue("李四");
Log.i("TAG", "containsValue(“values”)——>hashtable中是否包含相应的values----b2----:" + b2);
Log.i("TAG", "*******************************************************************");
/**
* isEmpty ——>map是否为空
*/
boolean b3 = hashtable.isEmpty();
Log.i("TAG", "isEmpty ——>hashtable是否为空----b3----:" + b3);
Log.i("TAG", "******************************************************************");
/**
* hashtable迭代方法1 ——>keySet()
* keySet()把Map集合中的所有键都保存到一个Set类型的集合对象中返回。
*/
Set<String> keyset = hashtable.keySet();
Iterator<String> i1 = keyset.iterator();
while (i1.hasNext()) {
String key = i1.next();
String value = hashtable.get(key);
Log.i("TAG", "keySet迭代key----:" + key + "----value----:" + value);
}
Log.i("TAG", "************************************************************");
/**
* hashtable迭代方法2 ——>values()
* values()把所有的值存储到一个Collection集合中返回,Collection<V> values():获取集合中所有值的集合。
* 缺点: values方法只能返回所有 的值,没有键。
*/
Collection<String> valuecollection = hashtable.values();
Iterator<String> i2 = valuecollection.iterator();
while (i2.hasNext()) {
String value = i2.next();
Log.i("TAG", "values迭代" + "value----:" + value);
}
Log.i("TAG", "******************************************************************");
/**
* hashtable迭代方法3 ——>entrySet()
* entrySet()这种方法既能够获取键又能够获取值。
*/
Set<Map.Entry<String, String>> keyvalue = hashtable.entrySet();
Iterator<Map.Entry<String, String>> i3 = keyvalue.iterator();
while (i3.hasNext()) {
Map.Entry<String, String> me = i3.next();
String key = me.getKey();
String value = me.getValue();
Log.i("TAG", "entrySet迭代key----:" + key + "----value----:" + value);
}
Log.i("TAG", "**********************************************************");
/**
* remove ——>通过key 删除对应的values
*/
hashtable.remove("2");//通过key 删除对应的值
Set<Map.Entry<String, String>> keyvalues = hashtable.entrySet();
Iterator<Map.Entry<String, String>> i3s = keyvalues.iterator();
while (i3s.hasNext()) {
Map.Entry<String, String> me = i3s.next();
String key = me.getKey();
String value = me.getValue();
Log.i("TAG", "通过key 删除对应的values后entrySet迭代key----:" + key + "----value----:" + value);
}
Log.i("TAG", "**********************************************************");
/**
* clear ——>清空hashtable中所有元素
*/
hashtable.clear();
Log.i("TAG", "清空hashtable中所有元素后len----:" + hashtable.size());
}
}
结果
I/TAG: get ——>根据key获取相应的values----str----:李四1
I/TAG: get ——>根据key获取相应的values----allstr----:李四1
I/TAG: *********************************************************************
I/TAG: size——>hashtable长度----len----:4
I/TAG: size——>hashtable长度----alllen----:4
I/TAG: ************************************************************************
I/TAG: containsKey(“key”)——>hashtable中是否包含相应的key----b1----:true
I/TAG: *******************************************************************
I/TAG: containsValue(“values”)——>hashtable中是否包含相应的values----b2----:false
I/TAG: *******************************************************************
I/TAG: isEmpty ——>hashtable是否为空----b3----:false
I/TAG: ******************************************************************
I/TAG: keySet迭代key----:4----value----:赵六1
I/TAG: keySet迭代key----:3----value----:王五1
I/TAG: keySet迭代key----:2----value----:李四1
I/TAG: keySet迭代key----:1----value----:张三1
I/TAG: ************************************************************
I/TAG: values迭代value----:赵六1
I/TAG: values迭代value----:王五1
I/TAG: values迭代value----:李四1
I/TAG: values迭代value----:张三1
I/TAG: ******************************************************************
I/TAG: entrySet迭代key----:4----value----:赵六1
I/TAG: entrySet迭代key----:3----value----:王五1
I/TAG: entrySet迭代key----:2----value----:李四1
I/TAG: entrySet迭代key----:1----value----:张三1
I/TAG: **********************************************************
I/TAG: 通过key 删除对应的values后entrySet迭代key----:4----value----:赵六1
I/TAG: 通过key 删除对应的values后entrySet迭代key----:3----value----:王五1
I/TAG: 通过key 删除对应的values后entrySet迭代key----:1----value----:张三1
I/TAG: **********************************************************
I/TAG: 清空hashtable中所有元素后len----:0
也就是说HashTable输出和插入的顺序不一样。即无序的。
以上可以看出HashMap和HashTable用法完全一样,只是底层实现不一样。
五.总结
Java容器实际上只有三种:List, Set,Map 但每种接口都有不同的实现版本.它们的区别可以归纳为由什么在背后支持它们.也就是说,你使用的接口是由什么样的数据结构实现的。
List的选择
ArrayList和LinkedList都实现了List接口。因此无论选择哪一个基本操作都一样。但ArrayList是由数组提供底层支持。而LinkedList是由双向链表实现的。所以,如果要经常向List里插入或删除数据LinkedList会比较好。否则应该用速度更快的ArrayList。
Set的选择
HashSet总是比TreeSet性能要好。而后者存在的理由就是它可以维持元素的排序状态。所以,如果需要一个排好序的Set时,才应该用TreeSet。
Map选择
同上,尽量选择HashMap。
附:Collection官方文档
https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html