文章目录
Java集合可分为Collection和Map两种体系
- Collection接口:单列数据,应以了存取一组对象的方法的集合
- List:元素有序,可重复的集合
- ArrayList:作为List接口的只要实现类,线程不安全,效率高,底层使用Object[] elementData存储
- LinkedList:对于频繁的插入,删除操作,使用此类效率高,底层使用双向链表存储
- Vector:作为List接口的古老实现类,线程安全,效率低,底层使用Object[] elementData存储
- Set:元素无序,不可重复的集合,如果将两个相同的元素加入集合中,add方法将返回false。
-
HashSet:
①不能保证元素的排列顺序
②顺序有可能发生变化,
③ 不是同步的
④集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相等
注意! 如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其 hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。- LinkedHashSet:作为HashSet的子类,LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
-
TreeSet:可以按照添加对象的指定属性,进行排序(自然排序or定制排序),不允许放入null。TreeSet判断两个对象是否相等的方式是两个对象通过equals方法返回true,或者通过CompareTo方法比较返回0
-
- List:元素有序,可重复的集合
- Map接口:双列数据,保存具有映射关系“key-value对”的集合—类似于函数映射 y = f(x)。
- HashMap:Map的主要实现类;线程不同步;可以存储null的key和value,允许一条记录的键为null,允许多条记录的值为null;
- LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历;在原有的HashMap底层结构基础上添加了一对指针,指向前一个和后一个结点;对于频繁的遍历操作,此类执行效率高于HashMap。
- TreeMap:保证按照添加的key-value进行排序,实现排序遍历,此时考虑自然排序或者定制排序。底层使用红黑树实现。
- Hashtable:
- Properties:常用来处理配置文件。
- HashMap:Map的主要实现类;线程不同步;可以存储null的key和value,允许一条记录的键为null,允许多条记录的值为null;
Collection接口继承树
Map接口继承树
Collection接口的常用方法
package com.pan;
import org.junit.Test;
import java.util.*;
class Person{
String name;
int age;
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
System.out.println("Person equals...");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//按照姓名从小到大排序
@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person p = (Person)o;
int compare = this.name.compareTo(p.name);
if(compare != 0){
return compare;
}
else{
return Integer.compare(this.age,p.age);
}
}
else{
throw new RuntimeException("输入类型不匹配");
}
}
}
public class CollectionTest {
@Test
public void test1(){
Collection coll = new ArrayList();
//add(Object e):将元素添加到coll中
coll.add("aa");
coll.add("ss");
coll.add(233);
coll.add(new Date());
System.out.println(coll.size());//4
Collection coll1 = new ArrayList();
coll1.add(456);
coll.addAll(coll1);
System.out.println(coll.size());//5
System.out.println(coll);//[aa, ss, 233, Fri Aug 13 16:41:37 GMT+08:00 2021, 456]
System.out.println(coll.isEmpty());//false
coll.clear();
System.out.println(coll.isEmpty());//true
}
@Test
public void test2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("Tom"));
coll.add(456);
coll.add(false);
coll.add(new Person("Jerry",10));
//contains(Object obj):判断当前集合中是否包含obj,判断时调用obj对象所在类的equals(),如果是自定义类,那么重写equals方法
boolean contains = coll.contains(123);
System.out.println(contains);//true
System.out.println(coll.contains(new String("Tom")));//true,String重写了equals()方法
System.out.println(coll.contains(new Person("jerry",10)));
// Person equals...
// Person equals...
// Person equals...
// Person equals...
// Person equals...
// false
//remove(Object obj):从当前集合中移除obj元素
coll.remove(123);
System.out.println(coll);//[Tom, 456, false, Person{name='Jerry', age=10}]
System.out.println("*************************");
coll.remove(new Person("Jerry",10));
System.out.println(coll);
// Person equals...
// Person equals...
// Person equals...
// Person equals...
// [Tom, 456, false]
//removeAll(Collecction coll1):从当前集合中移除coll1中所有的元素(移除交集)
Collection coll1 = Arrays.asList(123,456);
coll.removeAll(coll1);
System.out.println(coll);//[Tom, false]
}
@Test
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("Tom"));
coll.add(false);
coll.add(456);
coll.add(new Person("Jerry",10));
//retainAll(Collection coll1):保留当前集合和coll1的交集
Collection coll1 = Arrays.asList(123,456,789);
coll.retainAll(coll1);
System.out.println(coll);
// Person equals...
// Person equals...
// Person equals...
// [123, 456]
//equals(Object obj):要想返回true,需要当前集合和形参(是一个集合)的元素都相同
// 且如果是ArrayList还需要顺序相同
}
@Test
public void test4(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("Tom"));
coll.add(false);
coll.add(456);
coll.add(new Person("Jerry",10));
//hasCode():返回当前对象的哈希值
System.out.println(coll.hashCode());//574407810
//toArray():集合---》数组
Object[] objects = coll.toArray();
for(int i = 0; i < objects.length;i++){
System.out.println(objects[i]);
// 123
// Tom
// false
// 456
// Person{name='Jerry', age=10}
}
//数组---》集合:调用Arrays类的静态方法asList()
List<String> list = Arrays.asList(new String[]{"aa","bb","cc"});
System.out.println(list);//[aa, bb, cc]
}
}
使用迭代器和remove删除集合中的数据
package com.pan;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorTest {
//使用迭代器和remove删除集合中的数据
@Test
public void test1(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(new String("Tom"));
coll.add(false);
coll.add(456);
coll.add(new Person("Jerry",10));
Iterator iterator = coll.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
if("Tom".equals(obj)){
iterator.remove();
}
}
Iterator iterator1 = coll.iterator();
while(iterator1.hasNext()) {
System.out.println(iterator1.next());
// 123
// false
// 456
// Person{name='Jerry', age=10}
}
}
}
List接口中的常用方法
@Test
public void test5(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");
list.add(new Person("Ton",23));
list.add(123);
System.out.println(list);//[123, 456, AA, Person{name='Ton', age=23}, 123]
//void add(int index,Object ele):在index位置插入ele元素
list.add(1,"BB");
System.out.println(list);//[123, BB, 456, AA, Person{name='Ton', age=23}, 123]
//boolean addAll(int index, Collection eles):从index位置开始将eles中所有元素加入list中
List list1 = Arrays.asList(1,2);
list.addAll(list1);
System.out.println(list);//[123, BB, 456, AA, Person{name='Ton', age=23}, 123, 1, 2]
//Object get(int index):获取指定index位置的元素
System.out.println(list.get(2));//456
//int indexOf(Object obj):返回obj在集合中首次出现的位置,如果不存在返回-1
int index = list.indexOf(456);
System.out.println(index);//2
System.out.println(list.indexOf(888));//-1
//int lastIndexOf(Object obj):返回obj在集合中最后出现的位置
System.out.println(list.lastIndexOf("AA"));//3
//Object remove(int index):移除指定index位置的元素,并返回此元素
Object obj = list.remove(0);
System.out.println(list);//[BB, 456, AA, Person{name='Ton', age=23}, 123, 1, 2]
System.out.println(obj);//123
//Object set(int index, Object ele):设置指定index位置的元素为ele,并返回被修改了的元素
Object obj1 = list.set(1,444);
System.out.println(list);//[BB, 444, AA, Person{name='Ton', age=23}, 123, 1, 2]
System.out.println(obj1);//456
//List subList(int fronIndex, int toIndex):返回从fromIndex到toIndex位置的子集合,左闭右开
List subLsit = list.subList(1,4);
System.out.println(subLsit);//[444, AA, Person{name='Ton', age=23}]
}
Set集合
set:存储是无序的,不可重复的数据
- 无序性:存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值来添加的。
- 不可重复性
HashSet
添加元素的过程:
向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:
- 如果此位置上没有其他元素,则元素a添加成功
- 如果此位置上有其他元素b(或以链表形式存在的多个元素),则比较元素a与元素b的hash值:
- 如果hash值不相同,则元素a添加成功。
- 如果hash值相同,进而需要调用元素a所在类的equals()方法:
- equals()返回true,元素a添加失败
- equals()返回false,则元素a添加成功
说明:对于添加成功的情况,元素a于已经存在的指定索引位置上的数据以链表方式存储。
HashSet存储示例图:
@Test
public void test1(){
Set set = new HashSet();
set.add(456);
set.add(123);
set.add("AA");
set.add("Pan");
set.add(new Person("Jerry",20));
set.add(new Person("Jerry",20));//Person类需要重写equals方法和hashCode方法才能判断这两个是相等的
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}//AA 456 123 Pan Person{name='Jerry', age=20}
System.out.println(set.add(123));//false
}
LinkedHashSet
@Test
public void test2(){
Set set = new LinkedHashSet();
set.add(456);
set.add(123);
set.add("AA");
set.add("Pan");
set.add(new Person("Jerry",20));
set.add(new Person("Jerry",20));//Person类需要重写equals方法和hashCode方法才能判断这两个是相等的
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}//456 123 AA Pan Person{name='Jerry', age=20}
System.out.println(set.add(123));//false
}
TreeSet
- 向TreeSet中添加的数据,要求是相同类的对象
TreeSet的自然排序
Person类中需要重写以下方法:
//按照姓名从小到大排序
@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person p = (Person)o;
int compare = this.name.compareTo(p.name);
if(compare != 0){
return compare;
}
else{
return Integer.compare(this.age,p.age);
}
}
else{
throw new RuntimeException("输入类型不匹配");
}
}
@Test
public void test3(){
TreeSet tree = new TreeSet();
TreeSet tree1 = new TreeSet();
/*tree.add(123);//错误用法
tree.add(456);
tree.add("pan");
tree.add(new Person("zhou",23));*/
tree.add(34);
tree.add(-35);
tree.add(789);
tree.add(45);
Iterator iterator = tree.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");//-35 34 45 789
}
System.out.println();
tree1.add(new Person("Jerry",12));
tree1.add(new Person("Tom",17));
tree1.add(new Person("Alicy",18));
tree1.add(new Person("Pan",25));
tree1.add(new Person("Zhou",26));
tree1.add(new Person("Jerry",23));
Iterator iterator1 = tree1.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
// Person{name='Alicy', age=18}
// Person{name='Jerry', age=12}
// Person{name='Jerry', age=23}
// Person{name='Pan', age=25}
// Person{name='Tom', age=17}
// Person{name='Zhou', age=26}
}
TreeSet的定制排序
@Test
public void test4() {
//按照年龄从大到小排列
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Person && o2 instanceof Person) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
int a = -1 * Integer.compare(p1.getAge(), p2.getAge());
if(a != 0){
return a;
}
else{
return ((Person) o1).name.compareTo(((Person) o2).name);
}
} else {
throw new RuntimeException("输入的数据类型不匹配");
}
}
};
TreeSet tree1 = new TreeSet(com);
tree1.add(new Person("Jerry",12));
tree1.add(new Person("Tom",17));
tree1.add(new Person("Alicy",18));
tree1.add(new Person("Pan",25));
tree1.add(new Person("Zhou",23));
tree1.add(new Person("Jerry",23));
Iterator iterator1 = tree1.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
}
Map
Map中的key:无序的,不可重复的,使用Set存储所有的key,key所在的类要重写equals()和hashCode()(以HashMap为例)。
Map中的value:无序的,可重复的,使用Collection存储所有的value,value所在类要重写equals()。
一个键值对:key-value构成了一个Entry对象。
Map中的entry:无序的,不可重复的,使用Set存储所有的entry。
参考视频
HashMap的底层实现原理:
HashMap map = new HashMap();
首次调用put()方法时,底层创建长度为16的数组
…可能已经执行了多次put…
map.put(key1,value1):
首先,调用key1所在类的hashCode()方法计算key1的哈希值,此哈希值经过某种算法计算以后,得到在Node[]数组中的存放位置
- 如果此位置上的数据为空,此时的key1-value1添加成功。
- 如果此位置上的数据不为空,(意味着此位置上存在一个或者多个数据(以链表形式存在)),比较key1和已经存在的一个和多个数据的哈希值:
- 如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。
- 如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)
- 如果equals返回false:此时key1-value1添加成功。
- 如果equals返回false:使用value1替换value2
jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组长度>64时,此时此索引位置上的所有数据改为使用红黑树存储。
HashMap
@Test
public void test1(){
Map map = new HashMap();
//添加
map.put("AA",213);
map.put("Pan",234);
map.put("CC","rr");
map.put(23,54);
//修改
map.put("AA",89);
System.out.println(map);//{AA=89, CC=rr, 23=54, Pan=234}
Map map1 = new HashMap();
map1.put("Zhou",34);
map1.putAll(map);
System.out.println(map1);//{AA=89, CC=rr, 23=54, Pan=234, Zhou=34}
//remove(Object key)
Object value = map.remove("CC");
System.out.println(value);//rr
System.out.println(map);//{AA=89, 23=54, Pan=234}
}
/*元素查询的操作:
* Object get(Object key):获取指定key对应的value
* boolean containsKey(Object key):是否包含指定的key
* boolean containsValue(Object value):是否包含指定的value
* int size():返回map中key-value对的个数
* boolean isEmpty():
* boolean equals(Object obj):判断当前map和参数对象obj是否相等
* */
@Test
public void test2(){
Map map = new HashMap();
map.put("AA",213);
map.put("Pan",234);
map.put("CC","rr");
map.put(23,54);
System.out.println(map.get(23));//54
System.out.println(map.get(455));//null
boolean cc = map.containsKey("CC");
System.out.println(cc);//true
boolean gg = map.containsKey("gg");
System.out.println(gg);//false
boolean b = map.containsValue(213);
System.out.println(b);//true
boolean b1 = map.containsValue(555);
System.out.println(b1);//false
Map map1 = new HashMap();
map1.put("AA",213);
map1.put("Pan",234);
map1.put("CC","rr");
map1.put(23,54);
System.out.println(map.equals(map1));//true
}
/*元视图操作的方法:
*Set keySet():返回所有key构成的Set集合
* Collection values():返回所有value构成的Collection集合
* Set entrySet():返回所有key-value对构成得Set集合
* */
@Test
public void test3(){
Map map = new HashMap();
map.put("AA",213);
map.put("Pan",234);
map.put("CC","rr");
map.put(23,54);
//遍历所有的key:keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next() + " ");
}//AA CC 23 Pan
System.out.println();
//遍历所有value:values()
Collection values = map.values();
for(Object obj : values){
System.out.print(obj + " ");
}//213 rr 54 234
System.out.println();
//遍历所有的key-value:entrySet()
Set set1 = map.entrySet();
Iterator iterator1 = set1.iterator();
while(iterator1.hasNext()){
Object next = iterator1.next();
Map.Entry entry = (Map.Entry)next;
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
// AA-->213
// CC-->rr
// 23-->54
// Pan-->234
}
TreeMap
TreeMap自然排序
@Test
public void test4(){
TreeMap map = new TreeMap();
Person p1 = new Person("Tom",23);
Person p2 = new Person("Jerry",34);;
Person p3 = new Person("pan",21);
Person p4 = new Person("zhou",21);
Person p5 = new Person("Li",54);
map.put(p1,34);
map.put(p2,36);
map.put(p3,56);
map.put(p4,89);
map.put(p5,21);
Set set1 = map.entrySet();
Iterator iterator1 = set1.iterator();
while(iterator1.hasNext()){
Object next = iterator1.next();
Map.Entry entry = (Map.Entry)next;
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
// Person{name='Jerry', age=34}-->36
// Person{name='Li', age=54}-->21
// Person{name='Tom', age=23}-->34
// Person{name='pan', age=21}-->56
// Person{name='zhou', age=21}-->89
}
TreeMap定制排序
//TreeMap定制排序:按年龄从大到小
@Test
public void test5(){
TreeMap map = new TreeMap(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Person && o2 instanceof Person){
Person p1 = (Person) o1;
Person p2 = (Person) o2;
return -1*Integer.compare(p1.getAge(),p2.getAge());
}
throw new RuntimeException("输入类型不匹配");
}
});
Person p1 = new Person("Tom",23);
Person p2 = new Person("Jerry",34);;
Person p3 = new Person("pan",21);
Person p4 = new Person("zhou",21);
Person p5 = new Person("Li",54);
map.put(p1,34);
map.put(p2,36);
map.put(p3,56);
map.put(p4,89);
map.put(p5,21);
Set set1 = map.entrySet();
Iterator iterator1 = set1.iterator();
while(iterator1.hasNext()){
Object next = iterator1.next();
Map.Entry entry = (Map.Entry)next;
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
// Person{name='Li', age=54}-->21
// Person{name='Jerry', age=34}-->36
// Person{name='Tom', age=23}-->34
// Person{name='pan', age=21}-->89
Collections工具类
Collections是一个操作Set,List和Map等集合的工具类,其中还提供了一系列静态方法对集合元素进行排序,查询和修改等操作,还提供了对集合对象设置不可变,对集合对象实现同步控制等方法
/*
* reverse(List):反转List中元素的顺序
* shuffle(List):对List集合元素进行随机排序
* sort(List):根据元素的自然顺序对指定的List集合元素按升序排序
* sort(List,Comparator):根据指定的Comparator的顺序对List集合的元素进行排序
* swap(List,int,int):将指定List集合中的i处元素和j处元素进行交换
*
* Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
* Object max(Collection, Comparator):根据Comparator指定的顺序,返回给定集合中最大值
* Object min(Collection):
* Object min(Collection, Comparator):
* int frequency(Collection, Object):返回指定集合中指定元素出现的次数
* void copy(List dest, List src):将src中的内容复制到dest中
* boolean replaceAll(List list, Object oldVal,Object newVal):使用新值替换List对象的所有旧值
* */
@Test
public void test6(){
List list = new ArrayList();
list.add(123);
list.add(456);
list.add(456);
list.add(78);
list.add(-65);
list.add(0);
list.add(1);
System.out.println(list);
// Collections.reverse(list);
// Collections.shuffle(list);
// Collections.sort(list);
// Collections.swap(list,1,2);
// int frequency = Collections.frequency(list, 456);
// System.out.println(list);
List list1 = Arrays.asList(new Object[list.size()]);
System.out.println(list1);//[null, null, null, null, null, null, null]
Collections.copy(list1,list);
System.out.println(list1);//[123, 456, 456, 78, -65, 0, 1]
}