一、概述
对象用于封装特有数据,对象多了需要存储。如果对象的个数不确定,就使用集合容器进行存储。其长度可变,不可以存储基本数据类型值。
1.集合框架
集合容器因为内部的数据结构不同,有多种具体容器。不断的向上抽取,就形成了集合框架。如图为Collection的简化层次结构:
2.Colletion接口
Colletion接口常用方法:
1) 添加: add, addAll
2) 删除: remove, removeAll, clear
3) 判断: contains, containsAll, isEmpty
4) 获取: size, iterator
迭代器(Iterator)是对所有的Collection容器进行元素取出的公共接口。
Iterator iterator = iterable.iterator();
iterator.hasNext(); iterator.next();
5) 其他: retainAll, toArray
/* Collection常用方法示例*/
import java.util.*;
public class CollectionDemo {
public static void main(String[] args){
Collection coll = new ArrayList();
show(coll);
System.out.println("-------------------");
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
show (c1, c2);
}
public static void show(Collection coll){
//添加 add
coll.add("abc1");//boolean add(Object obj);
coll.add("abc2");
coll.add("abc3");
System.out.println("coll: "+coll);
//删除 remove
coll.remove("abc2");//boolean remove(Object obj);
System.out.println("coll: "+coll);
//清空 clear
//coll.clear();
//判断 isEmpty contains
System.out.println(coll.isEmpty()); //boolean isEmpty();
System.out.println(coll.contains("abc1")); //boolean contains(Object obj);
//获取 size
System.out.println(coll.size()); //int size();
}
public static void show(Collection c1, Collection c2){
//添加 addAll
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc4");
c2.add("abc2");
c2.add("abc6");
c2.add("abc7");
System.out.println("c1: "+c1);
System.out.println("c2: "+c2);
c1.addAll(c2); //boolean addAll(Collection coll);
//删除 removeAll
boolean a = c1.removeAll(c2); //boolean removeAll(Collection coll);
System.out.println("removeAll: "+a);
//判断 containsAll
boolean b = c1.containsAll(c2);
System.out.println("containsAll: "+b); //boolean containsAll(Collection coll);
//交集 retainAll
boolean c = c1.retainAll(c2); //boolean retainAll(Collection coll);
System.out.println("retain: "+c1);
}
}
/*
* 迭代器示例
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args){
Collection coll = new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
coll.add("abc4");
System.out.println(coll);
//调用集合中的迭代器方法,获取迭代器对象
Iterator it1 = coll.iterator();
while(it1. hasNext()){
System.out.println(it1.next());
}
//for循环结束,Iterator变量内存释放,更高效
for(Iterator it2 = coll.iterator(); it2.hasNext();){
System.out.println(it2.next());
}
}
}
二、List
Collection接口的两个子接口:
a.List: 记录元素的保存顺序,且允许有重复元素
b.Set: 不记录元素的保存顺序,且不允许有重复元素
List接口: 线性表(linear list)
List接口常用方法:
1) 添加: add, addAll
2) 删除: remove
3) 修改: set
4) 获取: get, indexOf, lastIndexOf, subList
/*
* List集合常用方法示例
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
import java.util.ListIterator;
public class ListDemo {
public static void main(String[] args){
List list = new ArrayList();
show(list);
}
public static void show(List list){
//添加
list.add("abc1"); //void add(index,element)
list.add("abc3");
list.add(1,"abc2");
System.out.println(list);
//删除
System.out.println("remove: "+list.remove(2)); //Object remove(index);
//修改
System.out.println("set: "+list.set(1,"abc8")); //Object set(index,element);
//获取
System.out.println(list.get(1)); //Object get(index);
System.out.println(list.indexOf("abc2")); //int indexOf(object);
System.out.println(list.lastIndexOf("abc8")); //int lastIndexOf(object);
System.out.println("sublist: "+list.subList(1, 2)); //List subList(fromIndex,toIndex);
//迭代器
Iterator it = list.iterator();
for (int x = 0; x < list.size(); x++){
System.out.println("get:"+list.get(x));
}
}
}
注:在迭代器过程中,不要使用集合操作元素,容易出现异常: java.util.ConcurrentModificationException。可以使用Iterator接口的子接口ListIterator来完成在迭代中对元素进行更多的操作,如下示例。
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args){
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
System.out.println("list: " + list);
//只有List集合具有这种在迭代过程中完成对元素增删改查的特有的迭代器
ListIterator it = list.listIterator();
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("abc3"))
it.add("abc9");
}
System.out.println("hasNext: "+it.hasNext());
System.out.println("hasPrevious: "+it.hasPrevious());
while(it.hasPrevious()){
System.out.println("previous: "+it.previous());
}
System.out.println("list: "+list);
}
}
List接口的主要实现类是 ArrayList. LinkedList, 以及早期的Vector
List实现类 | 内部数据结构 | 同步否 | 增删速度 | 查询速度 |
---|---|---|---|---|
ArrayList | 数组 | 否 | 慢 | 快 |
LinkedList | 链表 | 否 | 快 | 慢 |
Vector | 数组 | 是 | 慢 | 慢 |
LinkedList方法 | 旧方法 | jdk1.6版本后新方法 |
---|---|---|
添加 | addFirst(); addLast(); | offerFirst(); offerLast(); |
获取不移除 | getFirst(); getLast(); 如果链表为空,抛出NoSuchElementException | peekFirst(); peekLast();如果链表为空,返回null。 |
获取并移除 | removeFirst(); removeLast(); | pollFirst(); pollLast(); |
方法类型 | 可抛出异类的 | 返回元素的 |
---|---|---|
Insert(插入) | add(e) | offer(e) |
Remove(移除) | remove() | poll() |
Examine(检查) | element() | peek() |
两种重要的线性数据结构
1)栈 Stack
遵循“后进先出”(Last In First Out, LIFO)原则
包含三个方法
public Object push(Object item):将指定对象压入栈中。
Public Object pop():将 栈最上面的元素从栈中取出,并返回这个对象。
public boolean empty():判断栈中没有对象元素。
2)队列 Queue
遵循“先进先出”(First In First Out,FIFO)原则
固定在一端输入数据(称为入队),另一端输出数据(称为出队)。
/*
* 模拟队列
*/
import java.util.LinkedList;
class Queue{
private LinkedList link;
public Queue(){
link = new LinkedList();
}
//入队
public void enQueue(Object obj){
link.addLast(obj);
}
//出队
public Object outQueue(){
return link.removeFirst();
}
//判断队列是否为空
public boolean isNull(){
return link.isEmpty();
}
}
public class QueueDemo {
public static void main(String[] args){
Queue d = new Queue();
d.enQueue("abc1");
d.enQueue("abc2");
d.enQueue("abc3");
d.enQueue("abc4");
while(!d.isNull())
System.out.println(d.outQueue());
}
}
三、Set
Set接口中的方法和Collection一致。
1) HashSet:内部数据结构是哈希表,是不同步的。
2) TreeSet:可以对Set集合中的元素进行排序,是不同步的。其底层是用TreeMap来实现的
Set中对象不重复,即:hashCode()不等。如果hashCode()相等,再看equals或==是否为false。
/*
*ArrayList是无序列表,若要有序列表,则用LinkedHashSet
*/
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
public static void main(String[] args){
HashSet hs = new LinkedHashSet();
hs.add("abc");
hs.add("def");
hs.add("ghi");
Iterator it = hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
TreeSet的两种排序方式:
1)自然排序。让元素自身实现比较功能: 实现Comparable接口,覆盖compareTo方法。
/*TreeSet的两种排序方式*/
import java.util.TreeSet;
import java.util.Iterator;
import java.util.Comparator;
class Person implements Comparable{
private String name;
private int age;
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public int hashCode(){
return name.hashCode() + age * 39;
}
public boolean equals(Object obj){
if (this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public int compareTo(Object o){
Person p = (Person) o;
//先按照年龄排序,再按照姓名排序
int temp = this.age-p.age;
return temp == 0? this.name.compareTo(p.name):temp;
}
}
public class TreeSetDemo {
public static void main(String[] args){
TreeSet ts = new TreeSet();
ts.add(new Person("Amy",28));
ts.add(new Person("Beth",23));
ts.add(new Person("Cathy",21));
ts.add(new Person("Caroline",23));
ts.add(new Person("Milly",25));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName()+" : "+p.getAge());
}
}
}
2)比较器。让集合自身具备比较功能: 定义一个类实现Comparator接口,覆盖compare方法。
import java.util.TreeSet;
import java.util.Iterator;
import java.util.Comparator;
class Person implements Comparable{
private String name;
private int age;
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
public int hashCode(){
return name.hashCode() + age * 39;
}
public boolean equals(Object obj){
if (this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public int compareTo(Object o){
Person p = (Person) o;
int temp = this.age-p.age;
return temp == 0? this.name.compareTo(p.name):temp;
}
}
class ComparatorByName implements Comparator{
public int compare(Object o1, Object o2){
Person p1 = (Person) o1;
Person p2 = (Person) o2;
int temp = p1.getName().compareTo(p2.getName());
return temp == 0? p1.getAge()-p2.getAge():temp;
}
}
public class TreeSetDemo {
public static void main(String[] args){
TreeSet ts = new TreeSet(new ComparatorByName());
ts.add(new Person("Amy",28));
ts.add(new Person("Beth",23));
ts.add(new Person("Cathy",21));
ts.add(new Person("Caroline",23));
ts.add(new Person("Milly",25));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName()+" : "+p.getAge());
}
}
}
四、Map
Map接口,即映射,是键-值对(key-value pair)的集合,map集合中必须保证键的唯一性。
Map的层次结构如下图所示:
Map接口常用方法:
1) 添加
value put(key,value):返回前一个和key关联的值,如果没有返回null。
2) 删除
void clear():清空map集合。
value remove(Object key):根据指定的key删除这个键值对。
3)判断
boolean containsKey(key);
boolean containsValue(value);
boolean isEmpty();
4)获取
value get(key):通过键获取值,如果没有该键返回null。
int size():获取键值对个数。
import java.util.Map;
import java.util.HashMap;
public class MapMethodDemo {
public static void main(String[] args){
Map<Integer, String>map = new HashMap<Integer, String>();
method(map);
}
public static void method(Map<Integer, String> map){
//添加
System.out.println(map.put(23,"Lucy")); //null
System.out.println(map.put(21,"Glen")); //null
System.out.println(map);
map.put(28,"Richa");
map.put(25,"Samantha");
System.out.println(map);
//删除
//map.clear();
System.out.println("remove: "+map.remove(21));
//判断
System.out.println("containsKey: "+map.containsKey(23));
System.out.println("containsValue: "+map.containsKey("Richa"));
System.out.println("isEmpty: "+map.isEmpty());
//获取
System.out.println("get: "+map.get(23));
System.out.println("size: "+map.size());
}
}
获取Map集合元素并打印的三种方式:
1)通过keySet方法获取map中所有的键所在的set集合,再通过set的迭代器获取到每一个键。再对每一个键通过map集合的get方法获取其对应的值。
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
public class MapDemo {
public static void main(String[] args){
Map<Integer, String> map = new HashMap<Integer, String>();
method(map);
}
public static void method(Map<Integer, String>map){
map.put(23,"Lucy");
map.put(21,"Glen");
map.put(28,"Richa");
map.put(25,"Samantha");
Set<Integer> keySet = map.keySet();
Iterator<Integer> it = keySet.iterator();
while(it.hasNext()){
Integer key = it.next();
String value = map.get(key);
System.out.println(key+" : "+value);
}
}
}
2)Map转成Set——entrySet方法:该方法将键和值的映射关系作为对象存储到了Set集合中,而这个映射关系的类型就是Map.Entry类型。
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
public class MapDemo2 {
public static void main(String[] args){
Map<Integer, String> map = new HashMap<Integer, String>();
method(map);
}
public static void method(Map<Integer, String>map){
map.put(23,"Lucy");
map.put(21,"Glen");
map.put(28,"Richa");
map.put(25,"Samantha");
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Integer, String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+" : "+value);
}
}
}
3)只取value值时:将Map的value存入Collection集合,再通过Collection的迭代器获取value。
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
public class MapDemo3 {
public static void main(String[] args){
Map<Integer, String> map = new HashMap<Integer, String>();
method(map);
}
public static void method(Map<Integer, String>map){
map.put(23,"Lucy");
map.put(21,"Glen");
map.put(28,"Richa");
map.put(25,"Samantha");
Collection<String> values = map.values();
Iterator<String> it = values.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
Map子类 | 内部结构 | 线程 | Remark |
---|---|---|---|
Hashtable | 哈希表 | 同步 | 不允许null作为键,null作为值 |
HashMap | 哈希表 | 同步 | 允许null作为键,null作为值 |
TreeMap | 二叉树 | 不同步 | 可以对Map集合中的键进行排序 |
/*用LinkedHashMap输出Map内容跟存入顺序一致。*/
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo {
public static void main(String[] args){
HashMap<Integer, String> hm = new LinkedHashMap<Integer, String>();
hm.put(7, "Vance");
hm.put(3, "Emily");
hm.put(1, "Bill");
hm.put(5, "Alex");
Iterator<Map.Entry<Integer, String>> it = hm.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer, String> me = it.next();
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key + ": " +value);
}
}
}
/*
* 实例:输入1——7的数字,显示是星期几,并打印其英文表示
* 分析:星期几和英文是映射关系——优先考虑HashMap
*/
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
public static void main(String[] args){
String week = getWeek(1);
System.out.println(week);
System.out.println(getWeekByMap(week));
}
public static String getWeekByMap(String week){
Map<String, String> map = new HashMap<String, String>();
map.put("星期一","Mon");
map.put("星期二","Tue");
map.put("星期三","Wed");
map.put("星期四","Thu");
map.put("星期五","Fri");
map.put("星期六","Sat");
map.put("星期日","Sun");
return map.get(week);
}
public static String getWeek(int week){
if (week<1 || week>7)
throw new RuntimeException("没有对应的星期,请重新输入");
String[] weeks = {"","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
return weeks[week];
}
}
/*
* 实例:获取字符串中每一个字母出现的次数。
* 分析:映射关系——数组和Map;关系中没有顺序编号——Map;
* 键有顺序——TreeMap
*/
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class MapTest {
public static void main(String[] args){
String str = "fdqavcbsacdfss";
String s = getCharCount(str);
System.out.println(s);
}
public static String getCharCount(String str){
//将字符串变为字符数组
char[] chs = str.toCharArray();
//定义Map集合
Map<Character, Integer> map = new TreeMap<Character, Integer>();
for(int i = 0; i < chs.length; i++){
//如果不是字母,则不统计,跳出本次循环
if(!(chs[i]>='a' && chs[i]<='z' || chs[i] >='A' && chs[i] <='Z'))
continue;
//将数组中的字母作为键去查map表。返回值:map.contains(key)? null : key.equals(k))
Integer value = map.get(chs[i]);
int count = 0;
//如果map中已经存在,则count = key.equals(k);
if(value!=null){
count = value;
}
count++;
map.put(chs[i], count);
}
return mapToString(map);
}
private static String mapToString(Map<Character, Integer> map){
StringBuilder sb = new StringBuilder();
//定义迭代器对象迭代map中存储的键
Iterator<Character> it = map.keySet().iterator();
while(it.hasNext()){
Character key = it.next();
Integer value = map.get(key);
sb.append(key+"("+value+")");
}
return sb.toString();
}
}
四、Collections工具类
Collections:是集合框架的工具类,里面的方法都是静态的。
Collections常用方法:
1) 排序:sort, shuffle
2) 查找:binarySearch, max
3)替换:replace, replaceAll, fill, swap
4)反转:reverse, reverseOrder
5)同步:synchronizedList
import java.util.Collections;
import java.util.List;
import java.util.Comparator;
import java.util.ArrayList;
public class CollectionsDemo {
public static void main(String[] args){
demo();
}
public static void demo(){
List<String> list = new ArrayList<String>();
list.add("Caroline");
list.add("Amy");
list.add("Lisa");
list.add("Sandy");
list.add("Beth");
list.add("Daisy");
//对list集合进行指定顺序的排序
Collections.sort(list);
System.out.println(list);
Collections.sort(list, new ComparatorByLength());
System.out.println(list);
mySort(list, new ComparatorByLength());
System.out.println(list);
//shuffle: 使用默认随机源对指定列表进行置换
Collections.shuffle(list);
System.out.println(list);
//查找,找不到返回-1
int index = Collections.binarySearch(list, "Beth");
System.out.println("index = "+index);
//获取最大值
String max = Collections.max(list, new ComparatorByLength());
System.out.println("max = "+max);
//替换
Collections.replace(list,"Lisa","Milly");
System.out.println(list);
}
public static <T> void mySort(List<T> list, Comparator<? super T> comp){
for(int i = 0; i < list.size()-1; i++){
for (int j = i+1; j < list.size(); j++){
if(comp.compare(list.get(i), list.get(j))>0){
Collections.swap(list, i, j);
}
}
}
}
}
class ComparatorByLength implements Comparator<String>{
public int compare(String o1, String o2){
int temp = o1.length()-o2.length();
return temp == 0? o1.compareTo(o2):temp;
}
}
五、Arrays工具类
Arrays:集合框架的工具类,里面的方法都是静态的。
List asList(数组) 可以将数组转成集合,以便于增删操作。
使用Collection的 toArray 方法可以将集合转成数组。当指定类型的数组长度小于集合的size,那么该方法内部会创建一个新的数组。所以一般数组长度指定为集合的size。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ArraysDemo {
public static void main(String[] args){
//数组——>集合: List asList(array)
String[] arr = {"Amy", "Lucy", "Cathy"};
List<String> list = Arrays.asList(arr);
System.out.println(list.contains("Lucy"));
int[] arr1 = {31, 11, 51, 61};
List<int[]> list1 = Arrays.asList(arr1);
System.out.println(list1);
Integer[] arr2 = {31, 11, 51, 61};
List list2 = Arrays.asList(arr2);
System.out.println(list2);
//集合——>数组: toArray
List<String> list3 = new ArrayList<String>();
list3.add("abc1");
list3.add("abc2");
list3.add("abc3");
String[] arr3 = list3.toArray(new String[2]);
System.out.println(Arrays.toString(arr3));
}
}