1.集合结构图
2.数组和集合
3.Collection接口
3.1 Collection接口和常用方法
测试常用方法:对于remove,可删除对象也可按照下标删除,下标优先。
package com.collection_;
import java.util.ArrayList;
import java.util.List;
/**
* Created on 2021/6/22.
*
* @author Ryan_小王
*/
@SuppressWarnings({"all"})
public class Test {
public static void main(String[] args) {
List arrayList = new ArrayList();
arrayList.add("wcw");
arrayList.add("wj");
arrayList.add(10);
arrayList.add(0,12);
arrayList.remove(0);
System.out.println(arrayList);
System.out.println(arrayList.contains("wcw"));
System.out.println(arrayList.size());
System.out.println(arrayList.isEmpty());
arrayList.clear();
//添加多个元素
List arrayList1 = new ArrayList();
arrayList1.add(13);
arrayList1.add("wc");
arrayList.addAll(arrayList1);
System.out.println(arrayList.containsAll(arrayList1));
arrayList.removeAll(arrayList1);
System.out.println(arrayList);
}
}
3.2 Collection接口遍历元素
方式1:使用Iterator(迭代器)
- Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
- 实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
- Iterator仅用于遍历集合,Iterator本身并不存放对象。
package com.collection_;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Created on 2021/6/22.
*
* @author Ryan_小王
*/
public class CollectionIterator {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("wcw");
coll.add(12);
coll.add("hsp");
Iterator iterator = coll.iterator();
//hashNext():判断是否还有下一个元素
//快捷键itit
while (iterator.hasNext()) {
//next():1.下移动 2.将下移以后集合位置上的元素返回
Object obj = iterator.next();
System.out.println(obj);
}
}
}
方式2:使用增强for,在Collection集合
1.使用增强for,在Collection集合
2.增强for,底层仍然是迭代器
3.增强for可以理解成就是简化版本的迭代器遍历
4.增强for可以直接用于数组
package com.collection_;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created on 2021/6/22.
*
* @author Ryan_小王
*/
public class CollectionIterator {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("wcw");
coll.add(12);
coll.add("hsp");
//1.使用增强for,在Collection集合
//2.增强for,底层仍然是迭代器
//3.增强for可以理解成就是简化版本的迭代器遍历
for (Object obj: coll) {
System.out.println("元素:" + obj);
}
//增强for可以直接用于数组
int[] nums = {1, 2, 4};
for (int i: nums) {
System.out.println(i);
}
}
}
3.3 List
1.基本介绍
List接口是Collection接口的子接口,List集合类中元素有序、且可重复,支持索引访问,实现List接口常用的类有:ArrayList、LinkedList和Vector。
2.List接口常用方法
3.List三种遍历
多一个普通for循环获取:
1.使用增强for
2.使用Iterator(迭代器)
3.普通for循环,因为ArrayList底层其实是数组。
package com.collection_;
import java.util.ArrayList;
import java.util.List;
/**
* Created on 2021/6/22.
*
* @author Ryan_小王
*/
public class CollectionIterator {
public static void main(String[] args) {
List list = new ArrayList();
list.add("wcw");
list.add(12);
list.add("hsp");
//1.使用增强for,在Collection集合
//2.增强for,底层仍然是迭代器
//3.增强for可以理解成就是简化版本的迭代器遍历
for (Object obj: list) {
System.out.println("元素:" + obj);
}
Iterator iterator = coll.iterator();
//hashNext():判断是否还有下一个元素
//快捷键itit
while (iterator.hasNext()) {
//next():1.下移动 2.将下移以后集合位置上的元素返回
Object obj = iterator.next();
System.out.println(obj);
}
}
//使用普通for循环
for (int i=0; i < list.size(); i++) {
Object obj = list.get(i);
System.out.println(obj);
}
}
}
3.3.1 ArrayList扩容机制
1.ArrayList中维护了一个Object类型的数组elementData。
2.当创建ArrayList对象时,若使用无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如需再次扩容,则扩容elementData为1.5倍。
3.若使用自定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
无参构造器扩容流程图:
自定大小的构造器扩容机制:
第一次扩容就按照elementData的1.5倍扩容,整个流程和前面的一样。
3.3.2 Vector
1.基本介绍
Vector底层也是一个对象数组,Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized。在开发中,需要线程同步安全时,考虑使用Vector,若是单线程则可以使用ArrayList,效率更高一点。
2.ArrayList和Vector的比较
扩容机制不同,ArrayList不是线程安全,Vector是线程安全。
3.3.3 LinkedList
1.基本介绍
双向链表的定义和使用举例:
package com.collection_;
/**
* Created on 2021/6/23.
*
* @author Ryan_小王
*/
public class LinkedList01 {
public static void main(String[] args) {
Node jack = new Node("Jack");
Node mike = new Node("Mike");
Node smith = new Node("Smith");
//链接起来
jack.next = mike;
mike.next = smith;
smith.pre = mike;
mike.pre = jack;
//头指针和尾指针
Node first = jack;
Node last = smith;
System.out.println("======正向遍历======");
//正向遍历
while (true) {
if (first == null) {
break;
}
System.out.println(first);
first = first.next;
}
System.out.println("=======反向遍历=======");
//反向遍历
while (true) {
if (last == null) {
break;
}
System.out.println(last);
last = last.pre;
}
}
}
class Node {
public Object item;
public Node next;
public Node pre;
public Node(Object name) {
this.item = name;
}
public String toString() {
return "name=" +item;
}
}
2.ArrayList和LinkedList的比较
底层实现不同,ArrayList底层是可变数组,LinkedList底层实现是双向链表;增删效率不同,ArrayList增删效率较低,因为涉及到数组扩容,LinkedList增删效率较高,通过链表追加;改查效率不同,ArrayList较高,可直接索引找到,LinkedList较低,得从头开始。
3.4 Set
1.基本介绍
- 无序
- 不允许重复,只允许一个null
- Set接口实现类:HashSet、TreeSet、LinkedHashSet…
3.4.1 HashSet
1.基本介绍
- HashSet实现了Set接口,HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)
- 可以存放null值,但是只能有一个null
- HashSet不保证元素是有序的,取决于hash后,再确定索引的结果.(即,不能保证存放元素的顺序和取出顺序一致).
- 不能有重复元素/对象
2.底层机制说明
- HashSet添加元素底层实现(hashCode()+equals()).
- HashSet的扩容和转成红黑树机制
注意:加入第一个元素时候扩容到16,临界值为12,加入前八个到同一链表,此时数组还是16,加入第九个元素时候,数组扩容机制启动,数组扩容到32,临界值为24。
练习:在HashSet集合中添加员工,若name和age相同则不能添加,归根到底就是重写equals()和hashcode()方法。
package com.collection_;
import java.util.HashSet;
import java.util.Objects;
/**
* Created on 2021/6/25.
*
* @author Ryan_小王
*/
public class HashSetEx01 {
public static void main(String[] args) {
Employee wcw = new Employee("wcw", 12);
Employee wc = new Employee("wc", 12);
Employee wcw2 = new Employee("wcw", 12);
HashSet hashSet = new HashSet();
hashSet.add(wcw);
hashSet.add(wc);
hashSet.add(wcw2);
System.out.println(hashSet);
}
}
class Employee {
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
3.4.2 LinkedHashSet
1.基本说明
只是换成了双向链表,这样可以保证元素插入和取出顺序一致。其余的操作和扩容机制和HashSet一样。
注意:HashSet和LinkedHashSet一个是存放Node类型,一个是存放Entry类型。
HashSet的table维护的是Node类对象数组,Node是HashMap的静态内部类,插入的元素也是Node类的对象。
LinkedHashSet维护也是Node类对象数组,Node是HashMap的内部类,插入的元素是Entry类的对象。Entry是Node的子类。
2.全面说明
3.4.3 TreeSet
底层是TreeMap,可以排序,通过传入实现了Comparator接口的匿名内部类,重写compare()方法定制排序规则。
package com.collection_;
import java.util.Comparator;
import java.util.TreeSet;
/**
* Created on 2021/6/27.
*
* @author Ryan_小王
*/
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o2).compareTo((String)o1);
}
});
treeSet.add("tom");
treeSet.add("jack");
treeSet.add("so");
treeSet.add("bom");
treeSet.add("a");
System.out.println(treeSet);
}
}
//结果:[tom, so, jack, bom, a]
注意:重写了compare()
方法,会根据该方法判断元素是否加入,如下举例中,根据字符串的长度来排序,"bom"和"tom"
的长度都是3,则不会被加入,最终的结果为[a, so, tom, jack]
。
package com.collection_;
import java.util.Comparator;
import java.util.TreeSet;
/**
* Created on 2021/6/27.
*
* @author Ryan_小王
*/
@SuppressWarnings({"all"})
public class TreeSet_ {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
treeSet.add("tom");
treeSet.add("jack");
treeSet.add("so");
treeSet.add("bom");
treeSet.add("a");
System.out.println(treeSet);
}
}
//结果:[a, so, tom, jack]
4.Map接口
1.基本介绍
4.1 HashMap
1.Map接口的特点
EntrySet存放的Entry只是指向,真正存放数据的地方还是在HashMap的Node。
1.k-v最后是
HashMap$Node node = newNode(hash, key, value, null)
2.k-v为了方便程序员遍历,还会创建
EntrySet集合
,该集合存放的元素类型是Entry,而一个Entry对象就有k,v EntrySet<Entry<K,V>> 即:transientSet<Map.Entry<K,V>> entrySet
;
3.entrySet中,定义的类型是Map.Entry
,但是实际上存放的还是HashMap$Node
,这是因为static class Node<K, V> implements Map.Entry<K, V>
4.当把HashMap$Node对象存放到entrySet就方便我们的遍历,因为Map.Entry提供了重要的方法 ,K getKey(); V getValue()
//1.k-v最后是HashMap$Node node = newNode(hash, key, value, null)
//2.k-v为了方便程序员遍历,还会创建EntrySet集合,改集合存放的元素类型是Entry,而一个Entry
// 对象就有k,v EntrySet<Entry<K,V>> 即:transient Set<Map.Entry<K,V>> entrySet;
//3.entrySet中,定义的类型是Map.Entry,但是实际上存放的还是HashMap$Node
// 这是因为 static class Node<K, V> implements Map.Entry<K, V>
//4.当把HashMap$nODE对象存放到entrySet就方便我们的遍历,因为Map.Entry提供了重要的方法
// K getKey(); V getValue()
HashMap hashMap = new HashMap();
hashMap.put("no1", "wcw");
hashMap.put("no2", "wc");
Set set = hashMap.entrySet();
System.out.println(set.getClass()); //HashMap$EntrySet
for (Object obj: set) {
System.out.println(obj.getClass()); // HashMap$Node
Map.Entry entry = (Map.Entry) obj;
System.out.println("key=" + entry.getKey() + " value=" + entry.getValue());
}
2.Map接口常用方法
3.Map接口遍历
第一组:先取出所有的Key,通过Key取出所有的Value,取出的keyset是一个Set类型的集合,通过增强for或者迭代器遍历取出后,通过HashMap的get()方法获取value。
Set keyset = hashMap.keySet();
第二组:把所有的values取出,取出的为一个Collection类型的集合,同样通过增强for或者迭代器遍历取出value。
Collection coll = hashMap.values();
第三组:通过entrySet取出
Set entrySet = hashMap.entrySet();
for (Object obj: entrySet) {
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "-" + entry.getValue());
}
完整代码示例:
package com.collection_;
import java.util.*;
/**
* Created on 2021/6/26.
*
* @author Ryan_小王
*/
public class HashMap_ {
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put(1, "wcw");
hashMap.put(2, "wc");
hashMap.put(3, "wj");
System.out.println(hashMap);
//第一组:先取出所有的Key,通过Key取出所有的Value
Set keyset = hashMap.keySet();
//(1)增强for
System.out.println("===第一种方式===");
for (Object key: keyset) {
System.out.println(key + "-" + hashMap.get(key));
}
//(2)迭代器
System.out.println("===第二种方式===");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object object = iterator.next();
System.out.println(object + "-" + hashMap.get(object));
}
//第二组:把所有的values取出
Collection coll = hashMap.values();
//(1)增强for
System.out.println("取出所有的value(增强for)");
for (Object value: coll) {
System.out.println(value);
}
//(2)迭代器
System.out.println("取出所有vaule(迭代器)");
Iterator iterator1 = coll.iterator();
while (iterator1.hasNext()) {
Object value = iterator1.next();
System.out.println(value);
}
//第三组:entrySet
System.out.println("通过entrySet");
Set entrySet = hashMap.entrySet();
for (Object obj: entrySet) {
// System.out.println(obj);
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "-" + entry.getValue());
}
}
}
4.HashMap小结
5.HashMap底层机制
实际存储的为HashMap$Node
,它实现了Map$Entry
接口。
4.2 Hashtable
1.基本介绍
2.扩容机制
第一次加数据数组扩容为11,达到临界值8,再次加入数据时数组容量就乘以2然后加1变为23,临界值为23*0.75=17。
3.Hashtable和HashMap对比
4.3 Properties
4.4 TreeMap
可以排序,通过传入实现了Comparator接口的匿名内部类,重写compare()方法定制排序规则。
注意:重写了compare()
方法,会根据该方法判断元素是否加入,如下举例中,根据字符串的长度来排序,"bom"和"tom"
的长度都是3,则不会被加入,最终的结果为{a=5, so=3, tom=4, jack=2}
。
package com.collection_;
import java.util.Comparator;
import java.util.TreeMap;
/**
* Created on 2021/6/27.
*
* @author Ryan_小王
*/
@SuppressWarnings({"all"})
public class TreeMap_ {
public static void main(String[] args) {
TreeMap treeMap = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((String)o1).length() - ((String)o2).length();
}
});
treeMap.put("tom",1);
treeMap.put("jack",2);
treeMap.put("so",3);
treeMap.put("bom",4);
treeMap.put("a",5);
System.out.println(treeMap);
}
}
//结果:{a=5, so=3, tom=4, jack=2}
5.开发中如何选择集合实现类
6.Collections工具类
注:拷贝时候,dest的size()大小应该和原先数组一样。
package com.collection_;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* Created on 2021/6/22.
*
* @author Ryan_小王
*/
@SuppressWarnings({"all"})
public class ArrayList01 {
public static void main(String[] args) {
// 无参构造器
ArrayList arrayList= new ArrayList(8);
for (int i = 1; i <= 10; i++) {
arrayList.add(i);
}
for (int i = 1; i <=15; i++) {
arrayList.add(i);
}
arrayList.add(10);
System.out.println(arrayList);
//排序
Collections.sort(arrayList, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return (Integer)o2 - (Integer) o1;
}
});
//反转
Collections.reverse(arrayList);
System.out.println(arrayList);
//打乱
Collections.shuffle(arrayList);
System.out.println(arrayList);
//交换
Collections.swap(arrayList, 0, 1);
//个数
int a = Collections.frequency(arrayList, 1);
System.out.println(a);
//拷贝,注意dest大小应该和原先数组一样
ArrayList dest = new ArrayList(26);
for (int i=0; i < arrayList.size(); i++) {
dest.add("");
}
Collections.copy(dest, arrayList);
}
}