分类
Java集合可以大致分为集合和映射两大类:
集合(Collection)——一个独立元素的序列,其中的元素都遵循某些规则,集合又可以向下细分为:
列表(List)必须以插入的顺序保存元素;
集合(Set) 不能包含重复的元素;
队列(Queue)只能按照队列的形式添加和取出元素(先进先出)。
映射(Map)——一组成对的键值对对象,允许通过键值(Key)来查找值(Value):
数组列表(ArrayList)虽然只是存了值,但是可以通过数值来查找对象,因此可以看作把数字和对象关联在了一起;
映射(Map)允许使用一个对象来查找另一个对象,它把对象和对象关联到一起,称作字典(Dictionary),我们可以使用一个键对象来查找值对象,就像在通过拼音或者笔画来查字典一样。
根据Jdk1.8帮助文档的描述,我们可以把一些常用的集合类分类,如下图:
其中右上角加*号的为接口,为了区别于java.awt.List,我们在List前边加了util。
其中的每个类都实现了它们的接口和它们接口的父接口的方法(有点绕,实际上实现一个子接口就意味着必须把它的父接口的方法也实现了),也就是说,我们从最上边的的父接口的方法开始,逐级向下了解,就能更清晰的掌握这些集合的使用。
接下来,就来简单的介绍下Collection和Map的用法。
Collection
我们先来看看Collection都有哪些常用的方法:
添加:
boolean add(E e) 添加元素成功返回True
-
boolean addAll(Collection<? extends E> c)将自定集合的所有元素添加到此集合中。
ps:参数Collection<? extends E> c所有实现Collection的类。
查询:
boolean contains(Object o) 此集合包含此元素,则返回True。
boolean containsAll(Collection<?> c) 此集合包含指定集合的所有元素则返回True
boolean isEmpty() 此结合不包含元素(为空)则返回True
int size() 返回集合中的元素数
Object[] toArray() 返回包含所有元素的数组
删除:
void clean() 删除集合中的所有元素
boolean remove(Object o) 根据内容移除指定元素
题外话:虽然队列(Queue)和栈(Stack)都实现了这个方法,但是因为这个方法违背了它们本身应该有的性质,所以都不推荐使用(实测可行,但是文档里没把这个方法列出来)boolean removeAll(Collection<?> c)移除指定集合中包含的所有元素
retainAll(Collection<?> c)与上面是正好相反的,保留指定集合中的所有元素(其他移除)
示例:
接口Collection中拥有这些方法,这也就说明后边的实现类ArrayList、HashSet等等都可以使用这些方法。事不宜迟,赶紧试试~
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
public class ColletionTest {
public static void main(String[] args) {
// 因为只需要测试Collection的函数,所以这里使用向上转型
Collection<Integer> c1 = new ArrayList();
Collection<Integer> c2 = new LinkedList();
System.out.println("刚创建的c1时否为空? " + c1.isEmpty());
c1.add(1);c1.add(2);c1.add(3);
c2.add(1);c2.add(2);
System.out.println("c1的元素:" + c1);
System.out.println("c2的元素:" + c2);
System.out.println("c1的长度? " + c1.size());
Object[] o1 = c1.toArray();//转为数组
System.out.println("输出数组的第二个元素:"+(Integer)o1[1]);
System.out.println("c1是否包含2? " + c1.contains(2));
System.out.println("c1是否包含c2中所有元素? " + c1.containsAll(c2));
c1.remove(3);// 这里3会自动装包为Integer
System.out.println("c1的remove(3)d后的元素:" + c1);
System.out.println("c1是否和c2是否相同? " + c1.equals(c2));//有坑
System.out.println("clear()前c1是否为空? " + c1.isEmpty());
c1.clear();
System.out.println("clear()后c1是否为空? " + c1.isEmpty());
}
}
输出结果:
刚创建的c1时否为空? true
c1的元素:[1, 2, 3]
c2的元素:[1, 2]
c1的长度? 3
输出数组的第二个元素:2
c1是否包含2? true
c1是否包含c2中所有元素? true
c1的remove(3)d后的元素:[1, 2]
c1是否和c2是否相同? true
clear()前c1是否为空? false
clear()后c1是否为空? true
这里使用了List接口的ArrayList实现类和Queue接口的LinkedList实现类向上转型,但是不是所有Collection的子接口的实现类都能向上转型为Collection如抽象队列(AbstractQueue)。
还有一个坑就是equals方法,如果使用不同的实现类向上转型,equals的比对结果是不可信的,使用containsAll()来比对可能比较安全:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class EqualsTest {
public static void main(String[] args) {
Collection<Integer> c1 = new ArrayList();
Collection<Integer> c2 = new HashSet();
c1.add(1);c1.add(2);
c2.add(1);c2.add(2);
System.out.println("equals的比对结果"+c1.equals(c2));
System.out.println("优化后的比对结果"+(c1.containsAll(c2)&&c2.containsAll(c1)));
}
}
输出结果:
equals的比对结果false
优化后的比对结果true
关于Collection下List、Map、Stack、Queue的详情【坑】
Map
接下来我们要看看Map中常用的方法:
添加:
V put(K key, V value)将指定的键和指定的值相关联
void putAll(Map<? extends K,? extends V> m)将此Map的所有映射复制到指定的Map
查询:
boolean containsKey(Object key)此Map包含指定的键值,则返回True
boolean containsValue(Object value)如果此Map保函映射到指定值的键值,返回True
Set<Map.Entry<K,V>> entrySet()返回Map的Set视图
Set<K> keySet()返回Key的Set视图
Collection<V> values()返回值的Collection视图
boolean isEmpty()Map为空返回True
删除:
void clear()清除Map中的所有映射
V remove(Object key) 删除指定键的映射
default boolean remove(Object key, Object value)删除指定键值对的映射
修改:
- replace(K kay, V oldValue, V newValue)替换指定键指向的值
现在我们可以来练练手了:
import java.util.HashMap;
import java.util.Map;
public class MapTest {
public static void main(String[] args) {
Map<Integer,String> m = new HashMap<>();
m.put(1,"Jack");
m.put(1,"Tom");
m.put(2,"Lucy");
m.put(3,"Lily");
System.out.println("Map视图:"+m.entrySet());
System.out.println("Key视图:"+m.keySet());
System.out.println("Value视图:"+m.values());
m.remove(1);
System.out.println("执行remove(1)后:"+m.entrySet());
m.replace(2, "nameless");
System.out.println("替换键为2的映射后:"+m.entrySet());
System.out.println("执行clear()前Map是否为空:"+m.isEmpty());
m.clear();
System.out.println("在执行clear后:"+m.entrySet());
System.out.println("执行clear()之后Map是否为空:"+m.isEmpty());
}
}
输出结果:
Map视图:[1=Tom, 2=Lucy, 3=Lily]
Key视图:[1, 2, 3]
Value视图:[Tom, Lucy, Lily]
执行remove(1)后:[2=Lucy, 3=Lily]
替换键为2的映射后:[2=nameless, 3=Lily]
执行clear()前Map是否为空:false
在执行clear后:[]
执行clear()之后Map是否为空:true
可以注意到我们最先添加的Jack被后来的Tom给替代掉了,Map里是不允许一个键对应多个键值的,要想实现这个效果,可以将键值设计为List(其实甚至可以设置为Map)
package mapTest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListTest {
public static void main(String[] args) {
Map<Integer,List<String>> m = new HashMap<>();
List<String> l = new ArrayList<>();
l.add("Jack");l.add("Tom");
m.put(1,l);
System.out.println(m.entrySet());
}
}
有关Map实现类的详情【坑】