跟随狂神学Java
作者:joker2yue
链接:https://github.com/Joker2Yue/Joker2Yue-Blog
来源:Github
著作权归原作者所有。商业转载请联系原作者获得授权,非商业转载请注明出处。
第二十二天:集合
“简单之至则为雅致。”
狂神未更新,转动力节点(bilibili.com)
学习内容
什么是集合,有什么用?
数组其实就是一个集合,集合实际上就是一个容器。可以用来容纳其他类型的数据
集合在实际开发中使用较多
集合是一个容器,是一个载体,可以一次承载多个对象。在实际开发中,假设连接数据库,数据库中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后10个Java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来
集合中储存什么
集合不能直接储存基本数据类型,另外集合也不能直接存储Java对象,集合当中存储的都是Java对象的内存地址(或者说集合中存储的是引用)
不过有这样一条代码
看上去是存了一个int类型数据,实际上因为Java的自动装箱,会将100自动转换成Integer对象然后储存其引用
注意:集合在Java中本身是一个容器,是一个对象。集合任何时候存储的都是引用
比如:
new ArrayList();
创建一个集合对象,底层是数组
new LinkedList();
创建一个集合对象,底层是链表
new TreeSet();
创建一个集合对象,底层是二叉树
集合继承结构图(了解)
集合在java.util.*
下,所有的集合类和集合接口都在此包下
在Java中,集合分为两大类
单个方式存储元素
超级父接口是java.util.Collection;
键值对方式存储元素
超级父接口是java.util.Map;
Collection接口中的方法
Collection中能存放什么元素
没有使用“泛型”之前,Collection中可以存放Object的所有子类型
使用了“泛型”之后,Collection只能存放某个指定的具体的类型
集合中不能存储基本数据类型,也不能存储Java对象,只是存储Java对象的内存地址
Collection中的常用方法
方法摘要 |
|
boolean |
**[add](https://itmyhome.com/java-api/java/util/Collection.html#add(E))**(E e) 确保此 collection 包含指定的元素(可选操作)。 |
boolean |
**[addAll](https://itmyhome.com/java-api/java/util/Collection.html#addAll(java.util.Collection))**(Collection<? extends E> c) 将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 |
void |
**[clear](https://itmyhome.com/java-api/java/util/Collection.html#clear())**() 移除此 collection 中的所有元素(可选操作)。 |
boolean |
**[contains](https://itmyhome.com/java-api/java/util/Collection.html#contains(java.lang.Object))**(Object o) 如果此 collection 包含指定的元素,则返回 true 。 |
boolean |
**[containsAll](https://itmyhome.com/java-api/java/util/Collection.html#containsAll(java.util.Collection))**(Collection<?> c) 如果此 collection 包含指定 collection 中的所有元素,则返回 true 。 |
boolean |
**[equals](https://itmyhome.com/java-api/java/util/Collection.html#equals(java.lang.Object))**(Object o) 比较此 collection 与指定对象是否相等。 |
int |
**[hashCode](https://itmyhome.com/java-api/java/util/Collection.html#hashCode())**() 返回此 collection 的哈希码值。 |
boolean |
**[isEmpty](https://itmyhome.com/java-api/java/util/Collection.html#isEmpty())**() 如果此 collection 不包含元素,则返回 true 。 |
Iterator<E> |
**[iterator](https://itmyhome.com/java-api/java/util/Collection.html#iterator())**() 返回在此 collection 的元素上进行迭代的迭代器。 |
boolean |
**[remove](https://itmyhome.com/java-api/java/util/Collection.html#remove(java.lang.Object))**(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 |
boolean |
**[removeAll](https://itmyhome.com/java-api/java/util/Collection.html#removeAll(java.util.Collection))**(Collection<?> c) 移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 |
boolean |
**[retainAll](https://itmyhome.com/java-api/java/util/Collection.html#retainAll(java.util.Collection))**(Collection<?> c) 仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。 |
int |
**[size](https://itmyhome.com/java-api/java/util/Collection.html#size())**() 返回此 collection 中的元素数。 |
Object[] |
**[toArray](https://itmyhome.com/java-api/java/util/Collection.html#toArray())**() 返回包含此 collection 中所有元素的数组。 |
<T> T[] |
**[toArray](https://itmyhome.com/java-api/java/util/Collection.html#toArray(T[]))**(T[] a) 返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package com.joker_yue.javalearn.Collection;
import java.security.cert.CollectionCertStoreParameters; import java.util.ArrayList; import java.util.Collection; import java.util.Objects;
public class CollectionTest01 { public static void main(String[] args) {
Collection c = new ArrayList();
c.add(1200); c.add(3.14); c.add(new Student());
System.out.println("集合中元素的个数是"+c.size());
c.clear(); System.out.println("集合中元素的个数是"+c.size());
c.add("hello"); c.add("world"); c.add("Java"); c.add("Joker_yue");
System.out.println(c.contains("Java")); System.out.println(c.contains("hell"));
System.out.println("集合中元素的个数是"+c.size()); c.remove("Java"); System.out.println("集合中元素的个数是"+c.size());
System.out.println("C中是空的吗"+c.isEmpty());
Object[] obj = c.toArray();
for (int i = 0; i < obj.length; i++) { System.out.println("这是第"+i+"个元素,它是"+obj[i]); } } }
class Student{}
|
输出结果为:
1 2 3 4 5 6 7 8 9 10
| 集合中元素的个数是3 集合中元素的个数是0 true false 集合中元素的个数是4 集合中元素的个数是3 C中是空的吗false 这是第0个元素,它是hello 这是第1个元素,它是world 这是第2个元素,它是Joker_yue
|
Collection迭代
什么是迭代?重复反馈过程的活动,就是遍历
在目前学习中说所学习的迭代(遍历)方法,是所有Collection中通用的一种方法,这种方法在Map中不能用,在所有的Collection以及子类中能使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.joker_yue.javalearn.Collection;
import java.util.*;
public class CollectionTest02 { public static void main(String[] args) {
Collection c = new ArrayList();
c.add("abc"); c.add("def"); c.add(100); c.add(new Object());
Iterator it = c.iterator();
while (it.hasNext()){ Object obj = it.next(); System.out.println(obj); } } }
|
迭代器是一个对象 ,迭代器有两个方法:next()
和hasNext()
迭代器是通用的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.joker_yue.javalearn.Collection;
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator;
public class ColllectionTest03 { public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add(2); c1.add(3); c1.add(1); c1.add(4); c1.add(1);
Iterator it = c1.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
Collection c2 = new HashSet(); c2.add(100); c2.add(200); c2.add(300); c2.add(100); it = c2.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }
|
Contains方法解析
原理:底层调用了equals
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.joker_yue.javalearn.Collection;
import java.util.ArrayList; import java.util.Collection;
public class CollectionTest04 { public static void main(String[] args) {
Collection c= new ArrayList();
String s1 = new String ("abc"); c.add(s1);
String s2 = new String("def"); c.add(s2);
System.out.println("元素个数:"+c.size());
String x = new String ("abc"); System.out.println(c.contains(x)); } }
|
注意有时候要重写equals方法才能判断相等。将来调用equals方法的时候,一定是调用这个重写的方法
remove方法
remove也会调用equals
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.joker_yue.javalearn.SimpleDateFormat;
import java.util.ArrayList; import java.util.Collection;
public class CollectionTest03 { public static void main(String[] args) {
Collection cc = new ArrayList();
String s1 = new String("hello");
cc.add(s1);
String s2 = new String("hello"); cc.remove(s2);
System.out.println(cc.size()); } }
|
结果是
所以有时候使用remove
时也需要重写equals
迭代器对象的注意事项
元素每改动一次,应当重新获取迭代器对象,就像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.joker_yue.javalearn.SimpleDateFormat;
import java.sql.Array; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator;
public class CollectionTest06 { public static void main(String[] args) {
Collection c = new ArrayList();
c.add(1); c.add(2); c.add(3);
Iterator it = c.iterator(); while(it.hasNext()){ Object obj = it.next();
System.out.println(obj);
} } }
|
但是我们如何挨个删除里面的元素呢?我们可以使用迭代器删除元素,就像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package com.joker_yue.javalearn.SimpleDateFormat;
import java.sql.Array; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator;
public class CollectionTest06 { public static void main(String[] args) {
Collection c = new ArrayList();
c.add(1); c.add(2); c.add(3);
Iterator it = c.iterator(); while(it.hasNext()){ Object obj = it.next();
it.remove(); System.out.println(obj);
} } }
|
这是为什么?
获取的迭代器对象,迭代器用来遍历集合,此时相对于当前集合的状态拍了一个快照。迭代器迭代的时候会参照这个快照进行迭代
当我们直接使用集合删除元素的时候,会抛出异常,根本原因是没有更新迭代器。但是如果我们使用迭代器删除的时候,迭代器对象和元素对象都会被删除,就不会抛出异常
List接口独有方法
List集合存储元素特点:有序可重复
有序:List集合中的元素有下标,从0开始以1递增
可重复:相同元素可反复存储
List既然是Collection接口的子接口,那么肯定List接口有自己的“特色的”方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package com.joker_yue.javalearn.SimpleDateFormat;
import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Vector;
public class CollectionTest07 { public static void main(String[] args) {
List myList = new LinkedList();
myList.add("A"); myList.add("B"); myList.add("C"); myList.add("D");
myList.add(1,"King");
Iterator it = myList.iterator(); while(it.hasNext()){ Object obj = it.next(); System.out.println(obj); }
Object firstObj = myList.get(1); System.out.println(firstObj);
for (int i = 0; i < myList.size(); i++) { System.out.println(myList.get(i)); }
System.out.println(myList.indexOf("King"));
System.out.println(myList.lastIndexOf("C"));
myList.remove(1);System.out.println(myList.size());
myList.set(2,"Sorry"); for (int i = 0; i < myList.size(); i++) { System.out.println(myList.get(i)); } } }
|
ArrayList集合初始化容量以及扩容
ArrayList初始容量是10
ArrayList底层是Object类型的数组
ArrayList集合的扩容,是原容量的1.5倍
ArrayList集合的底层是数组,怎么优化?
尽可能少的扩容,因为数组扩容效率比较低,建议在ArrayList集合创建的时候预估要使用的容量,减少使用扩容的次数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.joker_yue.javalearn.SimpleDateFormat;
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List;
public class ArrayListTest02 { public static void main(String[] args) {
List myList1 = new ArrayList();
List myList2 = new ArrayList(100);
Collection c = new HashSet(); c.add(100); c.add(200); c.add(300); c.add(900); c.add(50);
List myList3 = new ArrayList(c); for (int i = 0; i < myList3.size(); i++) { System.out.println(myList3.get(i)); } } }
|
链表的优点和缺点
优点:随机增加元素的效率高(因为链表上的元素在空间存储上内存地址不连续,增加元素不涉及到大量元素的位移)
缺点:查询效率低,每一次查找整个元素的时候就要从节点开始向下查询(不通过数学表达式计算被查找元素的内存地址)
ArrayList:把检索发挥到极致(末尾添加元素效率还是很高的)
LinkedList:把随机增删发挥到极致
LinkedList源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package com.joker_yue.javalearn.SimpleDateFormat;
import java.util.ArrayList; import java.util.LinkedList; import java.util.List;
public class LinkedListTest { public static void main(String[] args) {
List list = new LinkedList(); list.add("a"); list.add("b"); list.add("c");
for (int i = 0; i < list.size(); i++) { Object obj = list.get(i); System.out.println(obj); }
List list2 = new LinkedList();
list2.add("123"); list2.add("456"); list2.add("789"); for (int i = 0; i < list2.size(); i++) { System.out.println(list2.get(i)); } } }
|
LinkedList总结
- 采用的底层原理是双向链表
- 对于链表数据结构,堆积增删效率较高,检索效率较低
- 链表中的元素在空间存储上,空间地址不连续
Vector源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| package com.joker_yue.javalearn.DataStruct;
import java.sql.Array; import java.util.*;
public class VectorTest { public static void main(String[] args) {
Vector vector = new Vector();
vector.add(1); vector.add(2); vector.add(3); vector.add(4); vector.add(5); vector.add(6); vector.add(7); vector.add(8); vector.add(9); vector.add(10);
vector.add(11);
Iterator it = vector.iterator(); while (it.hasNext()) { Object obj = it.next(); System.out.println(obj); }
List myList = new ArrayList();
Collections.synchronizedList(myList);
myList.add("111"); myList.add("222"); myList.add("333"); } }
|