Java集合
集合
Java的集合体系:Collection与Map。
Collection与Map都是抽象接口,List和Set也是抽象接口。ArrayList、Vector、LinkedList是List的具体实现类,HashSet、TreeSet是Set的实现类。HashMap、TreeMap是Map集合的实现类。
集合与数组的区别
长度上,数组长度不可变,集合可变;存储元素类型区别,数组可存任意类型,但一个数组中必须是同种类型。集合只能存引用类型,一个集合可存多种引用类型。
Collection接口
集合的顶层接口,有唯一的,有可重复的,有有序的,有无序的。
抽象方法
添 加:boolean add(E e);添加一个元素
boolean addAll(Collection<? extends E> c) 添加一个集合
删 除:void clear();暴力删除集合所有元素
boolean remove(Object o);删除一个元素
void removeAll(Collection c);删除一个集合
判 断:boolean contains(Object obj);判断是否包含某一个元素
boolean containsAll(Collection c);判断是否包含一个集合
boolean isEmpty();判断是否为空
获 取:Iterator <E> iterator();集合的迭代器
int size();获取集合长度
Object [ ] toArray()
子接口List
List集合体系特点:元素有序(存放与取出顺序一致);
元素可以重复;
可以通过索引得到元素;
特有方法:
添 加:boolean add(E e);
获 取:E get(int index);
删 除:E remove(int index) ;
boolean remove(Object o);
修 改:E set(int index, E element);
迭代器:ListIterator listIterator(int index);该方法可以从指定位置开始迭代
List的三大实现类
ArrayList LinkedList Vector
特点:
ArrayList:底层数据结构是数组,查询快,增删慢。线程不安全,效率高
Vector:底层数据结构是数组,查询快,增删慢。线程安全,效率低,查询稍慢。
LinkedList:底层数据结构是链表,查询慢,增删快。线程不安全,效率高。
ArrayList的使用:
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("Hello");
arrayList.add("Java");
//遍历有三种方法
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}
//迭代器遍历
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//增强for,源码也是迭代器
for (String s : arrayList) {
System.out.println(s);
}
Vector的使用:
Vector的特有方法:
添 加:void addElement(E obj);
获 取:E elementAt(int index);
Enumeration elements();枚举,与迭代器类似,hasMoreElements(),nextElement()方法。
Vector<String> vector = new Vector<>();
vector.add("Hello");
vector.add("Java");
//添加
vector.addElement("World");
for(String s:vector){
System.out.println(s);
}
//获取
Enumeration<String> elements = vector.elements();
while (elements.hasMoreElements()){
System.out.println(elements.nextElement());
}
LinkedList的使用:
LinkedList数据结构为链表,有特殊的方法:
添 加:void addFirst(E e);
void addLast(E e);
获 取:E getFirst();
E getLast();
删 除:E removeFirst();
E removeLast();
LinkedList<String> linkedList = new LinkedList<>();
//独特的链表结构,可以模拟一个栈的存储
linkedList.addFirst("first");
linkedList.addFirst("second");
linkedList.addFirst("third");
linkedList.addFirst("fourth");
linkedList.addFirst("last");
for(String s:linkedList){
System.out.println(s);
}
子接口Set
Set集合体系特点:元素不可以重复
元素无序(存入与取出顺序不一样,有独特的排序规则)
Set的实现类
HashSet TreeSet
HashSet:底层数据结构为哈希表,元素不可重复
TreeSet:底层数据结构为红黑树(平衡二叉树)元素不可重复且排序
HashSet的使用:
HashSet集合保证元素无序,主要由hashCode()和equals()方法来判断的。源码如下:
//add方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//put方法
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//继续调用putVal方法,并且用hash算法算出添加值的哈希值
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
在putVal方法里,先比较哈希值是否相等,再比较equals是否相等。所以有以下问题:在存引用对象时,若一个对象重复造了两次,所以哈希值不会相同,都可以存入集合,这样元素便重复了。
要想保证不重复,就需要让两个重复对象的哈希值相同,所以根据对象的成员变量重写类的hashCode方法即可,但同时需要重写equals方法,判断对象成员变量是否相同,这样就可以排除重复元素。
public static void main(String[] args) {
HashSet<People> hs = new HashSet<>();
People p1 = new People(12, "one");
People p2 = new People(13, "two");
People p3 = new People(12, "one");
//在没有重写hashCode和equals时都可以添加成功
System.out.println("P1的添加"+hs.add(p1));//结果:P1的添加true
System.out.println("P2的添加"+hs.add(p2));//结果:P2的添加true
System.out.println("P3的添加"+hs.add(p3));//结果:P3的添加true
}
public static void main(String[] args) {
HashSet<People> hs = new HashSet<>();
People p1 = new People(12, "one");
People p2 = new People(13, "two");
People p3 = new People(12, "one");
//在重写hashCode和equals后
System.out.println("P1的添加"+hs.add(p1));//结果:P1的添加true
System.out.println("P2的添加"+hs.add(p2));//结果:P2的添加true
System.out.println("P3的添加"+hs.add(p3));//结果:P3的添加false
}
TreeSet集合的使用:
TreeSet集合对元素进行排序,分为自然排序和比较器排序。自然排序就是默认排序规则,比较器排序需要实现Comparator接口。
当存放Integer类型时,Integer类已经实现了Comparator接口,可以使用自然排序。
//自然排序
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(10);
ts.add(0);
ts.add(25);
ts.add(0);
for (Integer i : ts) {
System.out.println(i);
}
//输出结果0 10 25
}
//比较器排序
public static void main(String[] args) {
People p1 = new People(12, "one");
People p2 = new People(10, "two");
People p3 = new People(14, "three");
//TreeSet<People> ts = new TreeSet<>();
//不实现比较器时报异常java.lang.ClassCastException: com.IO.People cannot be cast to java.lang.Comparable
//下面采用匿名内部类方法实现接口
TreeSet<People> ts = new TreeSet<>(new Comparator<People>() {
@Override
public int compare(People o1, People o2) {
return o1.age-o2.age;
}
});
ts.add(p1);
ts.add(p2);
ts.add(p3);
for(People p:ts){
System.out.println(p.name+"---"+p.age);
}
//输出结果
//two---10
//one---12
//three---14
}
Map接口
Map接口与Collection一样为顶层接口,与Collection系列集合不同之处是:Map集合存的都是键值对,以key,value形式成对出现。第二个不同是,Map键唯一,而Collection只有Set系列保证元素唯一。第三个不同,Map数据结构针对的是键,Collection数据结构针对的是元素。
Map接口抽象方法:
添 加:V put(K key, V value);返回值为该键对应的原值,也可以作为修改的方法。
删 除:void clear();
V remove(Object key);
判 断:boolean containsKey(Object key);
boolean containsValue(Object value);
boolean isEmpty();
获 取:V get(Object key);根据键获取值
Set keySet();获取键的集合
Collection values();获取值的集合
Set<Map.Entry<K,V>> entrySet();获取键值对对象
遍历方法:
因为Map比较特殊,所以遍历时也比较特殊。有两种方法,一:获取键的集合,用键获取值;二:获取键值对对象的集合,遍历集合获取键和值。
实现类HashMap、TreeMap
实现类有HashMap、TreeMap,还有LinkedHashMap、Hashtable(没有按驼峰命名规则),特点如下:
HashMap:哈希表的数据结构,元素无序唯一(无序指的是存放去取的无序,唯一对键有效)。
LinkedHashMap:也使用了链表,元素有序唯一。
Hashtable:源于jdk1.0,在jdk1.2被改造在Map接口下。与HashMap相似。线程安全,效率低,是同步的,不允许null键和null值;HashMap线程不安全,效率高,允许null键与null值。
TreeMap:键排列有序,也是自然排序和比较器排序。
HashMap使用:
public static void main(String[] args) {
HashMap<Integer, String> hm = new HashMap<>();
hm.put(1,"Hello");
hm.put(2,"Java");
hm.put(3,"World");
//遍历--用键获取值
for(int i=1;i<4;i++){
System.out.println("key="+i+",value="+hm.get(i));
}
//遍历--获取键值对对象
Set<Map.Entry<Integer, String>> entries = hm.entrySet();
for(Map.Entry a:entries){
System.out.println("key="+a.getKey()+",value="+a.getValue());
}
//输出结果
//key=1,value=Hello
//key=2,value=Java
//key=3,value=World
//key=1,value=Hello
//key=2,value=Java
//key=3,value=World
}
TreeMap的使用:
public static void main(String[] args) {
People p1 = new People(12, "康康");
People p2 = new People(10, "迈克");
People p3 = new People(11,"玛利亚");
//用TreeMap存这三个人,作为键,值为每个人的爱好。默认以年龄排序
TreeMap<People, String> tm = new TreeMap<>(new Comparator<People>() {
@Override
public int compare(People o1, People o2) {
return o1.age-o2.age;
}
});
tm.put(p1,"篮球");
tm.put(p2,"游泳");
tm.put(p3,"唱歌");
//遍历
Set<Map.Entry<People, String>> entries = tm.entrySet();
for(Map.Entry mess:entries){
System.out.println(mess.getKey().toString()+"的爱好是"+mess.getValue());
}
//输出结果
//People{age=10, name='迈克'}的爱好是游泳
//People{age=11, name='玛利亚'}的爱好是唱歌
//People{age=12, name='康康'}的爱好是篮球
}
集合工具类
为了方便集合操作,Java也提供了一个工具类------Collections。
几个常用的方法:
static <T extends Comparable<? super T>> void sort(List list) 对list集合排序,默认自然排序
static <T extends Comparable<? super T>> void sort(List list,Comparator<? super T> c) 比较器排序
static int binarySearch(List<? extends Comparable<? super T>> list, T key) 二分查找
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) Collection集合最大值
static void reverse(List<?> list) 集合反转
static void shuffle(List<?> list) 随机置换元素
总结
集合从大的分有两大类,Collection和Map,前者存储的都是单一元素,后者为键值对。使用Collection时,若对元素没有要求,ArrayList最佳。若需要保证元素唯一,可以用HashSet;若同时需要排序时,采用TreeSet。在使用Map时,有排序要求就使用TreeMap,没有就用HashMap。
此篇文章仅仅用于对自我知识总结,以便复习,也希望对集合知识不是清晰的Java学习者有一点帮助。作者也是Java萌新,望大佬多多指点。
附带一个模拟扑克牌发牌的程序,用于练习。
链接:https://pan.baidu.com/s/15G32-CSr-lWBxazcameQYg
提取码:g3hl