Java集合 - 集合知识点总结概述
集合概述
概念:对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能。
和数组的区别:
数组长度固定,集合长度不固定。
数组可以存储基本类型和引用类型,集合只能存储引用类型。
- 位置: java.util.*;
Collection体系集合
Collection父接口
特点:代表一组任意类型的对象,无序、无下标、不能重复。
方法:
boolean add(Object obj) //添加一个对象。
boolean addAll(Collection c) //讲一个集合中的所有对象添加到此集合中。
void clear() //清空此集合中的所有对象。
boolean contains(Object o) //检查此集合中是否包含o对象。
boolean equals(Object o) //比较此集合是否与指定对象相等。
boolean isEmpty() //判断此集合是否为空。
boolean remove(Object o) //在此集合中移除o对象。
int size() //返回此集合中的元素个数。
Object[] toArray() //姜此集合转换成数组。
1 /**
2 * Collection接口的使用(一)
3 * 1.添加元素
4 * 2.删除元素
5 * 3.遍历元素
6 * 4.判断
7 */
8 public class Demo01 {
9 public static void main(String[] args) {
10 //创建集合
11 Collection collection = new ArrayList();
12
13 // * 1.添加元素
14 collection.add("西瓜");
15 collection.add("苹果");
16 collection.add("榴莲");
17 System.out.println(collection.size());
18 System.out.println(collection.toString());
19
20 // * 2.删除元素
21 collection.remove("西瓜");
22 System.out.println("删除之后:"+collection.size());
23
24 // * 3.遍历元素
25 //3.1 使用增强for
26 for (Object object:collection) {
27 String s = (String) object;
28 System.out.println(s);
29 }
30 //3.2 使用迭代器(迭代器专门用来遍历集合的一种方式)
31 //hasnext();判断是否有下一个元素
32 //next();获取下一个元素
33 //remove();删除当前元素
34 Iterator it = collection.iterator();
35 while (it.hasNext()){
36 String s = (String) it.next();
37 System.out.println(s);
38 //删除操作
39 //collection.remove(s);引发错误:并发修改异常
40 //iterator.remove();应使用迭代器的方法
41
42 // * 4.判断
43 System.out.println(collection.contains("苹果"));//true 是否存在苹果
44 System.out.println(collection.isEmpty());//false 是否有数据,没有数据为true,有数据为false
45 }
46 }
47 }
1 /**
2 * Collection接口的使用(二)
3 * 1.添加元素
4 * 2.删除元素
5 * 3.遍历元素
6 * 4.判断
7 */
8 public class Demo02 {
9 public static void main(String[] args) {
10
11 //创建Collection对象
12 Collection collection = new ArrayList();
13
14 //创建Student对象
15 Student s1 = new Student("张三",18);
16 Student s2 = new Student("李四",19);
17 Student s3 = new Student("王五",20);
18
19 //1.添加数据
20 collection.add(s1);
21 collection.add(s2);
22 collection.add(s3);
23 //collection.add(s3);可重复添加相同对象
24 System.out.println("元素个数为:"+collection.size());
25 System.out.println(collection.toString());
26
27 //2.删除数据
28 collection.remove(s1);
29 System.out.println("元素个数为:"+collection.size());
30 System.out.println(collection.toString());
31
32 //3.遍历数据
33 //3.1 增强for循环
34 for (Object object:collection) {
35 Student s = (Student) object;
36 System.out.println(object);
37 }
38
39 //3.2 迭代数据
40 //迭代过程中不能使用Collection的删除方法,即Collection.remove()
41 Iterator it = collection.iterator();
42 while (it.hasNext()){
43 Student s = (Student) it.next();
44 System.out.println(s);
45 //删除
46 //it.remove();
47 }
48
49 //4判断
50 System.out.println(collection.contains("张三"));//false
51 System.out.println(collection.contains(s2));//true
52 System.out.println(collection.isEmpty());//false
53 }
54 }
1 /**
2 * 学生类
3 */
4 public class Student {
5 private String name;
6 private int age;
7
8 //有参构造
9 public Student(String name, int age) {
10 this.name = name;
11 this.age = age;
12 }
13
14 //无参构造
15 public Student() {
16 }
17
18 //重写toString
19 @Override
20 public String toString() {
21 return "Student{" +
22 "name='" + name + '\'' +
23 ", age=" + age +
24 '}';
25 }
26
27 //get/set静态属性
28 public String getName() {
29 return name;
30 }
31
32 public void setName(String name) {
33 this.name = name;
34 }
35
36 public int getAge() {
37 return age;
38 }
39
40 public void setAge(int age) {
41 this.age = age;
42 }
43 }
Collection子接口
List集合
特点:有序、有下标、元素可以重复。
方法:
void add(int index,Object o) //在index位置插入对象o。
boolean addAll(index,Collection c) //将一个集合中的元素添加到此集合中的index位置。
Object get(int index) //返回集合中指定位置的元素。
List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之间的集合元素。
1 /**
2 * List子接口的使用(一)
3 * 特点:1.有序有下标 2.可以重复
4 *
5 * 1.添加元素
6 * 2.删除元素
7 * 3.遍历元素
8 * 4.判断
9 * 5.获取位置
10 */
11 public class Demo03 {
12 public static void main(String[] args) {
13
14 //1.创建list集合对象
15 List list = new ArrayList<>();
16
17 //2.添加元素
18 list.add("迪迦");
19 list.add("艾斯");
20 list.add(0,"赛文");//根据index下标插入数据
21 System.out.println("元素个数为:"+list.size());
22 System.out.println(list.toString());
23
24 //3.删除数据
25 list.remove(1);
26 //list.remove("迪迦");意思同上,一个是根据角标,一个是根据内容
27 System.out.println("删除之后:"+list.size());
28 System.out.println(list.toString());
29
30 //4.遍历元素
31 //4.1 因为有下标,所以可以使用for循环
32 for (int i = 0; i < list.size(); i++) {
33 System.out.println(list.get(i));
34 }
35 //4.2 使用增强for循环
36 for (Object object:list) {
37 String s = (String) object;
38 System.out.println(s);
39 }
40 //4.3 使用迭代器
41 Iterator it = list.iterator();
42 while (it.hasNext()){
43 String s = (String) it.next();
44 System.out.println(s);
45 }
46 //4.4 使用列表迭代器
47 ListIterator listIterator = list.listIterator();
48 //从前往后遍历
49 while (listIterator.hasNext()){
50 String s = (String) listIterator.next();
51 System.out.println(s);
52 }
53 //从后往前遍历(此时“遍历指针”已经指向末尾了)
54 while (listIterator.hasPrevious()){
55 String s = (String) listIterator.previous();
56 System.out.println(s);
57 }
58
59 //5.判断
60 System.out.println(list.contains("赛文"));//true
61 System.out.println(list.isEmpty());//false
62
63 //6.获取位置
64 System.out.println(list.indexOf("艾斯"));//1
65 }
66 }
1 /**
2 * List子接口的使用(二)
3 * 1.添加元素
4 * 2.删除元素
5 * 3.遍历元素
6 * 4.判断
7 * 5.获取位置
8 */
9 public class Demo04 {
10 public static void main(String[] args) {
11 List list = new ArrayList<>();
12 //1.添加基本类型数字数据(自动装箱)
13 list.add(10);
14 list.add(20);
15 list.add(30);
16 list.add(40);
17 list.add(40);
18 System.out.println("元素个数为:"+list.size());
19 System.out.println(list.toString());
20
21 //2.删除数据
22 list.remove(0);//根据下标删除
23 //list.remove(40);下标越界
24 list.remove(new Integer(40));//根据内容删除,将基本类型转成引用类型
25 System.out.println("删除后:"+list.size());
26 System.out.println(list.toString());
27
28 //3.遍历元素
29 //3.1 使用for循环
30 for (int i = 0; i < list.size(); i++) {
31 System.out.println(list.get(i));
32 }
33 //3.2 使用增强for循环
34 for (Object object:list) {
35 int s = (int) object;
36 System.out.println(s);
37 }
38 //3.3 使用迭代器
39 Iterator it = list.iterator();
40 while (it.hasNext()){
41 int s = (int) it.next();
42 System.out.println(s);
43 }
44 //3.4 使用列表迭代器
45 ListIterator listIterator = list.listIterator();
46 //从前往后遍历
47 while (listIterator.hasNext()){
48 int s = (int) listIterator.next();
49 System.out.println(s);
50 }
51 //从后往前遍历(此时“遍历指针”已经指向末尾了)
52 while (listIterator.hasPrevious()){
53 int s = (int) listIterator.previous();
54 System.out.println(s);
55 }
56
57 //4.判断
58 System.out.println(list.contains(20));//true
59 System.out.println(list.isEmpty());//false
60
61 //5.获取位置
62 System.out.println(list.indexOf(30));//1
63
64 //6.补充方法sublist,根据角标范围,返回集合元素,含头不含尾
65 List list1 = list.subList(0,2);
66 System.out.println(list1.toString());//20,30
67 }
68 }
List实现类
ArrayList【重点】
- 数组结构实现,查询快、增删慢;
- JDK1.2版本,运行效率快、线程不安全。
1 /**
2 * ArrayList的使用
3 * 存储结构:数组;
4 * 特点:查找遍历速度快,增删慢。
5 * 1.添加元素
6 * 2.删除元素
7 * 3.遍历元素
8 * 4.判断
9 * 5.查找
10 */
11 public class Demo05 {
12 public static void main(String[] args) {
13 ArrayList arrayList = new ArrayList<>();
14 //1.添加元素
15 Student s1 = new Student("钢铁侠",3);
16 Student s2 = new Student("蜘蛛侠",4);
17 Student s3 = new Student("蝙蝠侠",5);
18 arrayList.add(s1);
19 arrayList.add(s2);
20 arrayList.add(s3);
21 arrayList.add(s3);
22 System.out.println("元素个数:"+arrayList.size());
23 System.out.println(arrayList.toString());
24
25 //2.删除元素
26 arrayList.remove(s3);
27 System.out.println("删除后:"+arrayList.size());
28 System.out.println(arrayList.toString());
29 //arrayList.remove(new Student("唐", 21));
30 //注:这样可以删除吗(不可以)?显然这是两个不同的对象。
31 //假如两个对象属性相同便认为其是同一对象,那么如何修改代码?
32
33 //3.遍历元素
34 //3.1使用迭代器
35 Iterator it = arrayList.iterator();
36 while (it.hasNext()){
37 Student s = (Student) it.next();
38 System.out.println(s);
39 }
40 //3.2使用列表迭代器
41 ListIterator listIterator = arrayList.listIterator();
42 //从前往后遍历
43 while (listIterator.hasNext()){
44 Student s = (Student) listIterator.next();
45 System.out.println(s);
46 }
47 //从后往前遍历
48 while (listIterator.hasPrevious()){
49 Student s = (Student) listIterator.previous();
50 System.out.println(s);
51 }
52
53 //4.判断
54 System.out.println(arrayList.isEmpty());//false
55 //System.out.println(arrayList.contains(new Student("钢铁侠", 3)));
56 //注:与上文相同的问题。
57
58 //5.查找
59 System.out.println(arrayList.indexOf(s1));
60 }
61 }
注:Object里的equals(this==obj)用地址和当前对象比较,如果想实现代码中的问题,可以在学生类中重写equals方法:
1 //重写equls方法
2 @Override
3 public boolean equals(Object obj) {
4 //1.是否为同一对象
5 if (this == obj){
6 return true;
7 }
8 //2.判断是否为空
9 if (obj == null){
10 return false;
11 }
12 //3.判断是否是Student类型
13 if (this instanceof Student){
14 Student s = (Student) obj;
15 //4.比较属性
16 if (this.name.equals(s.getName())&&this.age==s.age){
17 return true;
18 }
19 }
20 return false;
21 }
ArrayList源码分析:
默认容量大小:
private static final int DEFAULT_CAPACITY = 10;
存放元素的数组:
transient Object[] elementData;
实际元素个数:
private int size;
创建对象时调用的无参构造函数:
1 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
2 //Arraylist无参构造方法
3 public ArrayList() {
4 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
5 }
这段源码说明当你没有向集合中添加任何元素时,集合容量为0。那么默认的10个容量怎么来的呢?这就得看看add方法的源码了:
1 public boolean add(E e) {
2 ensureCapacityInternal(size + 1); // Increments modCount!!
3 elementData[size++] = e;
4 return true;
5 }
假设你new了一个数组,当前容量为0,size当然也为0。这时调用add方法进入到ensureCapacityInternal(size + 1);
该方法源码如下:
1 private void ensureCapacityInternal(int minCapacity) {
2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
3 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
4 }
5
6 ensureExplicitCapacity(minCapacity);
7 }
由于一开始Arraylist的无参构造方法,就是将 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给了 elementData ,所以if的条件是成立的。
if语句中 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 就是在 DEFAULT_CAPACITY 和 minCapacity 中返回一个最大的参数, DEFAULT_CAPACITY 是Arrarylist中一开始就定义的静态常量,大小为10。 minCapacity 传入的值为size+1也就是 1
DEFAULT_CAPACITY值大,因此返回DEFAULT_CAPACITY的值为10,
这个值作为参数又传入ensureExplicitCapacity()
方法中,进入该方法查看源码:
1 private void ensureExplicitCapacity(int minCapacity) {
2 modCount++;
3
4 // overflow-conscious code
5 if (minCapacity - elementData.length > 0)
6 grow(minCapacity);
7 }
我们先不要管modCount这个变量,可以理解为这个变量是记录数组修改次数。
因为elementData数组长度为0,minCapacity为10,所以if条件成立,调用grow方法,重要的部分来了,这个代码就是数组扩容的代码,现在我们进入到grow方法的源码中:
1 private void grow(int minCapacity) {
2 // overflow-conscious code
3 int oldCapacity = elementData.length; //oldCapactity=0
4 int newCapacity = oldCapacity + (oldCapacity >> 1); //oldCapacity=0;(oldCapacity >> 1)0右移一位还是0;因此newCapacity=0
5 if (newCapacity - minCapacity < 0) //0-10=-10,if条件成立
6 newCapacity = minCapacity; //newCapacity=10
7 if (newCapacity - MAX_ARRAY_SIZE > 0) //MAX_ARRAY_SIZE这个值大家也可以进去看下,是好几个亿,这个条件基本上永远不会成立。可以忽略不看,了解即可
8 newCapacity = hugeCapacity(minCapacity);
9 // minCapacity is usually close to size, so this is a win:
10 elementData = Arrays.copyOf(elementData, newCapacity); //copyOf(elementData,newCapacity)创建一个新的数组elementDate,数组长度为newCapacity即就是10
11 }
这个方法先声明了一个oldCapacity变量将数组长度赋给它,其值为0;又声明了一个newCapacity变量其值为oldCapacity+一个增量
,可以发现这个增量是和原数组长度有关的量,当然在这里也为0。第一个if条件满足,newCapacity的值为10(这就是默认的容量,不理解的话再看看前面)。第二个if条件不成立,也可以不用注意,因为MAX_ARRAY_SIZE的定义如下:
这个值太大了以至于第二个if条件没有了解的必要。
最后一句话就是为elementData数组赋予了新的长度,Arrays.copyOf()
方法返回的数组是新的数组对象,原数组对象不会改变,该拷贝不会影响原来的数组。copyOf()
的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值。
这时候再回到add的方法中,接着就向下执行elementData[size++] = e,将add传入的值e赋值给数组elementData,下标index为[size++]。
到这里为止关于ArrayList就讲解得差不多了,当数组长度为10的时候你们可以试着过一下源码,查一下每次的增量是多少(答案是每次扩容为原来的1.5倍)。
Vector
数组结构实现,查询快、增删慢;
JDK1.0版本,运行效率慢、线程安全。
1 /**
2 * Vector的演示使用
3 *
4 *1.添加数据
5 *2.删除数据
6 *3.遍历
7 *4.判断
8 */
9 public class Demo01 {
10 public static void main(String[] args) {
11 //1.创建Vector对象
12 Vector v = new Vector<>();
13
14 //2.添加数据
15 v.add("孙悟空");
16 v.add("猪八戒");
17 v.add("沙和尚");
18 System.out.println("元素个数为:"+v.size());
19 System.out.println(v.toString());
20
21 //3.删除数据
22 v.remove("沙和尚");
23 //v.remove(2);效果同上
24 System.out.println("删除后:"+v.size());
25 System.out.println(v.toString());
26
27 //4.遍历
28 //使用枚举
29 Enumeration elements = v.elements();
30 while (elements.hasMoreElements()){
31 System.out.println(elements.nextElement());
32 }
33
34 //5.判断
35 System.out.println(v.isEmpty());
36 System.out.println(v.contains("孙悟空"));
37 }
38 }
LinkedList
- 链表结构实现,增删快,查询慢。
1 /**
2 * LinkedList的用法
3 * 存储结构:双向链表
4 * 1.创建对象
5 * 2.添加元素
6 * 3.删除元素
7 * 4.遍历
8 * 5.判断
9 */
10 public class Demo01 {
11 public static void main(String[] args) {
12 //1.创建LinkedList对象
13 LinkedList link = new LinkedList<>();
14
15 //2.添加元素
16 Student s1 = new Student("python",1);
17 Student s2 = new Student("Java",2);
18 Student s3 = new Student("go",3);
19 link.add(s1);
20 link.add(s2);
21 link.add(s3);
22 link.add(s3);
23 System.out.println("元素个数为:"+link.size());
24 System.out.println(link.toString());
25
26 //3.删除元素
27 link.remove(s3);
28 link.remove(new Student("go",3));
29 System.out.println("删除后:"+link.size());
30 System.out.println(link.toString());
31
32 //4.遍历
33 //4.1 使用for循环遍历
34 for (int i = 0; i < link.size(); i++) {
35 System.out.println(link.get(i));
36 }
37 //4.2 使用增强for
38 for (Object object:link) {
39 Student s = (Student) object;
40 System.out.println(s.toString());
41 }
42 //4.3 使用迭代器
43 Iterator it = link.iterator();
44 while (it.hasNext()){
45 System.out.println(it.next());
46 }
47 //4.4 使用列表迭代器
48 ListIterator listIterator = link.listIterator();
49 //从前往后遍历
50 while (listIterator.hasNext()){
51 System.out.println(listIterator.next());
52 }
53 //从后往前遍历
54 while (listIterator.hasPrevious()){
55 System.out.println(listIterator.previous());
56 }
57
58 //5.判断
59 System.out.println(link.isEmpty());
60 System.out.println(link.contains(s1));
61 System.out.println(link.contains(new Student("Java",2)));
62 }
63 }
LinkedList源码分析
LinkedList首先有三个属性:
- 链表大小:
transient int size = 0;
- (指向)第一个结点/头结点:
transient Node<E> first;
- (指向)最后一个结点/尾结点:
transient Node<E> last;
关于Node类型我们再进入到类里看看:
1 private static class Node<E> {
2 E item;
3 Node<E> next;
4 Node<E> prev;
5
6 Node(Node<E> prev, E element, Node<E> next) {
7 this.item = element;
8 this.next = next;
9 this.prev = prev;
10 }
11 }
首先item存放的是实际数据;next指向下一个结点而prev指向上一个结点。
Node带参构造方法的三个参数分别是前一个结点、存储的数据、后一个结点,调用这个构造方法时将它们赋值给当前对象。
LinkedList是如何添加元素的呢?先看看add方法:
1 public boolean add(E e) {
2 linkLast(e);
3 return true;
4 }
进入到linkLast方法:
1 void linkLast(E e) {
2 final Node<E> l = last;
3 final Node<E> newNode = new Node<>(l, e, null);
4 last = newNode;
5 if (l == null)
6 first = newNode;
7 else
8 l.next = newNode;
9 size++;
10 modCount++;
11 }
假设刚开始new了一个LinkedList对象,first和last属性都为空,调用add进入到linkLast方法。
首先创建一个Node变量 l 将last(此时为空)赋给它,然后new一个newNode变量存储数据,并且它的前驱指向l,后继指向null;再把last指向newNode。如下图所示:
如果满足if条件,说明这是添加的第一个结点,将first指向newNode:
至此,LinkedList对象的第一个数据添加完毕。假设需要再添加一个数据,我们可以再来走一遍,过程同上不再赘述,图示如下:
ArrayList和LinkedList区别
- ArrayList:必须开辟连续空间,查询快,增删慢。
- LinkedList:无需开辟连续空间,查询慢,增删快。
泛型概述
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法。
- 语法:
- <T,…> T称为类型占位符,表示一种引用类型。
- 好处:
- 提高代码的重用性。
- 防止类型转换异常,提高代码的安全性。
泛型类
1 /**
2 * 泛型类
3 * 语法:类名<T>
4 * T是类型占位符,表示一种引用类型,编写多个使用逗号隔开
5 *
6 */
7 public class MyGeneric<T> {
8 //1.创建泛型变量
9 //不能使用new来创建,因为泛型是不确定的类型,也可能拥有私密的构造方法
10 T t;
11 //2.泛型作为方法的参数
12 public void show(T t){
13 System.out.println(t);
14 }
15
16 //3.泛型作为方法的返回值
17 public T getT(){
18 return t;
19 }
20 }
1 /**
2 * 注意:
3 * 1.泛型只能使用引用类型
4 * 2.不同泛型类型的对象不能相互赋值
5 */
6 public class TestGeneric {
7 public static void main(String[] args) {
8 //使用泛型类创建对象
9 MyGeneric<String> stringMyGeneric = new MyGeneric<>();
10 stringMyGeneric.t = "葫芦娃";
11 stringMyGeneric.show("火娃");
12
13 MyGeneric<Integer> integerMyGeneric = new MyGeneric<>();
14 integerMyGeneric.t=20;
15 integerMyGeneric.show(30);
16 Integer integer = integerMyGeneric.getT();
17 System.out.println(integer);
18 }
19 }
泛型接口
1 /**
2 * 泛型接口
3 * 语法:接口名<T>
4 * 注意:不能创建泛型静态常量
5 */
6 public interface MyInterface<T> {
7 //创建常量
8 String nameString="金刚大芭比";
9
10 //接口方法
11 T server(T t);
12 }
1 /**
2 * 实现接口时确定泛型类
3 */
4 public class MyInterfaceImpl implements MyInterface<String> {
5
6 @Override
7 public String server(String s) {
8 System.out.println(nameString);
9 System.out.println(s);
10 return s;
11 }
12 }
1 //测试
2 public class Application {
3 public static void main(String[] args) {
4 MyInterfaceImpl myInterface = new MyInterfaceImpl();
5 myInterface.server("xxx");
6 }
7 }
1 /**
2 * 实现接口时不确定泛型类
3 */
4 public class MyInterfaceImpl2<T> implements MyInterface<T>{
5 @Override
6 public T server(T t) {
7 System.out.println(nameString);
8 System.out.println(t);
9 return t;
10 }
11 }
1 //测试
2 public class Application {
3 public static void main(String[] args) {
4 MyInterfaceImpl2<Integer> integerMyInterfaceImpl2 = new MyInterfaceImpl2<>();
5 integerMyInterfaceImpl2.server(20);
6 }
7 }
泛型方法
1 /**
2 * 泛型方法
3 * 语法:<T> 返回类型
4 */
5 public class MyGenericMethod {
6 public <T> void show(T t){
7 System.out.println("泛型方法"+t);
8 }
9 }
1 //测试
2 public class Application {
3 public static void main(String[] args) {
4 MyGenericMethod myGenericMethod = new MyGenericMethod();
5 myGenericMethod.show("金刚");
6 myGenericMethod.show(18);
7 }
8 }
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型指尖引用不能相互赋值,泛型不存在多态。
之前我们在创建LinkedList类型对象的时候并没有使用泛型,但是进到它的源码中会发现:
1 public class LinkedList<E>
2 extends AbstractSequentialList<E>
3 implements List<E>, Deque<E>, Cloneable, java.io.Serializable
4 {//略
它是一个泛型类,而我之前使用的时候并没有传递,说明java语法是允许的,这个时候传递的类型是Object类,虽然它是所有类的父类,可以存储任意的类型,但是在遍历、获取元素时需要原来的类型就要进行强制转换。这个时候就会出现一些问题,假如往链表里存储了许多不同类型的数据,在强转的时候就要判断每一个原来的类型,这样就很容易出现错误。
Set集合概述
Set子接口
- 特点:无序、无下标、元素不可重复。
- 方法:全部继承自Collection中的方法。
1 /**
2 * 测试Set接口的使用
3 * 特点:1.无序,没有下标;2.重复
4 * 1.添加数据
5 * 2.删除数据
6 * 3.遍历【重点】
7 * 4.判断
8 */
9 public class Demo01 {
10 public static void main(String[] args) {
11 Set<String> set = new HashSet<>();
12 //1.添加数据
13 set.add("火娃");
14 set.add("金娃");
15 set.add("木娃");
16 set.add("水娃");
17 //set.add("水娃");无法添加元素相同数据
18 System.out.println("元素个数为:"+set.size());
19 System.out.println(set.toString());
20
21 //2.删除数据
22 set.remove("水娃");
23 System.out.println("删除后:"+set.size());
24 System.out.println(set.toString());
25
26 //3.遍历
27 //3.1 使用增强for循环
28 for (String s:set) {
29 System.out.println(s);
30 }
31 //3.2 使用迭代器
32 Iterator<String> iterator = set.iterator();
33 while (iterator.hasNext()){
34 System.out.println(iterator.next());
35 }
36
37 //4. 判断
38 System.out.println(set.isEmpty());//false
39 System.out.println(set.contains("火娃"));//true
40 }
41 }
Set实现类
HashSet【重点】
- 基于HashCode计算元素存放位置。
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
1 /**
2 * 人类
3 */
4 public class Person {
5 private String name;
6 private int age;
7
8 public Person(String name, int age) {
9 this.name = name;
10 this.age = age;
11 }
12
13 public Person() {
14 }
15
16 public String getName() {
17 return name;
18 }
19
20 public void setName(String name) {
21 this.name = name;
22 }
23
24 public int getAge() {
25 return age;
26 }
27
28 public void setAge(int age) {
29 this.age = age;
30 }
31
32 @Override
33 public String toString() {
34 return "Person{" +
35 "name='" + name + '\'' +
36 ", age=" + age +
37 '}';
38 }
39 }
1 /**
2 * HashSet集合的使用
3 * 存储结构:哈希表(数组+链表+红黑树)
4 * 1.添加元素
5 * 2.删除元素
6 * 3.遍历
7 * 4.判断
8 */
9 public class Demo02 {
10 public static void main(String[] args) {
11 HashSet<Person> hashSet=new HashSet<>();
12 Person p1=new Person("tang",21);
13 Person p2=new Person("he", 22);
14 Person p3=new Person("yu", 21);
15 //1.添加元素
16 hashSet.add(p1);
17 hashSet.add(p2);
18 hashSet.add(p3);
19 //重复,添加失败
20 hashSet.add(p3);
21 //直接new一个相同属性的对象,依然会被添加,不难理解。
22 //假如相同属性便认为是同一个对象,怎么修改?
23 hashSet.add(new Person("yu", 21));
24 System.out.println(hashSet.toString());
25 //2.删除元素
26 hashSet.remove(p2);
27 //3.遍历
28 //3.1 增强for
29 for (Person person : hashSet) {
30 System.out.println(person);
31 }
32 //3.2 迭代器
33 Iterator<Person> iterator=hashSet.iterator();
34 while (iterator.hasNext()) {
35 System.out.println(iterator.next());
36 }
37 //4.判断
38 System.out.println(hashSet.isEmpty());
39 //直接new一个相同属性的对象结果输出是false,不难理解。
40 //注:假如相同属性便认为是同一个对象,该怎么做?
41 System.out.println(hashSet.contains(new Person("tang", 21)));
42 }
43 }
注:hashSet存储过程:
- 根据hashCode计算保存的位置,如果位置为空,则直接保存,否则执行第二步。
- 执行equals方法,如果方法返回true,则认为是重复,拒绝存储,否则形成链表。
存储过程实际上就是重复依据,要实现“注”里的问题,可以重写hashCode和equals代码:
1 @Override
2 public int hashCode() {
3 final int prime = 31;
4 int result = 1;
5 result = prime * result + age;
6 result = prime * result + ((name == null) ? 0 : name.hashCode());
7 return result;
8 }
9 @Override
10 public boolean equals(Object obj) {
11 if (this == obj)
12 return true;
13 if (obj == null)
14 return false;
15 if (getClass() != obj.getClass())
16 return false;
17 Person other = (Person) obj;
18 if (age != other.age)
19 return false;
20 if (name == null) {
21 if (other.name != null)
22 return false;
23 } else if (!name.equals(other.name))
24 return false;
25 return true;
26 }
hashCode方法里为什么要使用31这个数字大概有两个原因:
- 31是一个质数,这样的数字在计算时可以尽量减少散列冲突。
- 可以提高执行效率,因为31*i=(i<<5)-i,31乘以一个数可以转换成移位操作,这样能快一点;但是也有网上一些人对这两点提出质疑。
TreeSet
- 基于排序顺序实现不重复。
- 实现了SortedSet接口,对集合元素自动排序。
- 元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过CompareTo方法确定是否为重复元素。
1 /**
2 * 使用TreeSet保存数据
3 * 存储结构:红黑树
4 * 要求:元素类必须实现Comparable接口,compareTo方法返回0,认为是重复元素
5 */
6 public class Demo01 {
7 public static void main(String[] args) {
8
9 TreeSet<Person> treeSet = new TreeSet<>();
10
11 Person p1 = new Person("it",12);
12 Person p2 = new Person("he",12);
13 Person p3 = new Person("she",12);
14
15 //1.添加元素
16 treeSet.add(p1);
17 treeSet.add(p2);
18 treeSet.add(p3);
19 treeSet.add(p3);//相同无法添加
20 //注:直接添加会报类型错误,需要实现Comparable接口
21 System.out.println("元素个数为:"+treeSet.size());
22 System.out.println(treeSet.toString());
23
24 //2.删除元素
25 treeSet.remove(p3);
26 treeSet.remove(new Person("she",12));
27 System.out.println(treeSet.toString());
28
29 //3.遍历
30 //3.1 增强for循环
31 for (Person person:treeSet) {
32 System.out.println(person);
33 }
34 //3.2 迭代器
35 Iterator<Person> iterator = treeSet.iterator();
36 while (iterator.hasNext()){
37 System.out.println(iterator.next());
38 }
39
40 //4.判断
41 System.out.println(treeSet.contains(new Person("it",12)));
42 }
43 }
运行报错,因为treeset是红黑树,当前代码没有定义比较的属性,需要重写Comparable方法
先查看Comparable接口的源码,发现只有一个compareTo抽象方法,在Person类中实现它:
1 public class Person implements Comparable<Person> {
2 @Override
3 public int compareTo(Person o) {
4 int n1 = this.getName().compareTo(o.getName());//名字相同,返回0,不同返回其他数字
5 int n2 = this.getAge()-o.getAge();//比较年龄
6 return n1==0?n2:n1;//名字相同,返回n2,名字不同,返回n1
7 }
8 }
再次运行TreeSet的Demo01,运行成功
除了实现Comparable接口里的比较方法,还有另外一种方法,TreeSet也提供了一个带比较器Comparator的构造方法,使用匿名内部类来实现它:
1 /**
2 * TreeSet的使用
3 * Comparator:实现定制比较(比较器)
4 */
5 public class Demo02 {
6 public static void main(String[] args) {
7 TreeSet<Person> person = new TreeSet<Person>(new Comparator<Person>() {
8 @Override
9 public int compare(Person o1, Person o2) {
10 // 先按年龄比较
11 // 再按姓名比较
12 int n1=o1.getAge()-o2.getAge();
13 int n2=o1.getName().compareTo(o2.getName());
14 return n1==0?n2:n1;
15 }
16 });
17 Person p1 = new Person("it",12);
18 Person p2 = new Person("he",12);
19 Person p3 = new Person("she",12);
20
21 //1.添加元素
22 person.add(p1);
23 person.add(p2);
24 person.add(p3);
25 //注:直接添加会报类型错误,需要实现Comparable接口
26 System.out.println("元素个数为:"+person.size());
27 System.out.println(person.toString());
28 }
29 }
接下来我们来做一个小案例:
1 /**
2 * 要求:使用TreeSet集合实现字符串按照长度进行排序
3 * helloworld tangrui hechengyang wangzixu yuguoming
4 * Comparator接口实现定制比较
5 */
6 public class Demo03 {
7 public static void main(String[] args) {
8 TreeSet<String> s = new TreeSet<>(new Comparator<String>() {
9 @Override
10 //1.先比较长度
11 //2.在比较字符串
12 public int compare(String o1, String o2) {
13 int n1 = o1.length()-o2.length();
14 int n2 = o1.compareTo(o2);
15 return n1==0?n2:n1;
16 }
17 });
18 s.add("hello world");
19 s.add("hello Java");
20 s.add("hello Python");
21 System.out.println(s.toString());
22 }
23 }
Map体系集合
Map接口的特点:
- 用于存储任意键值对(Key-Value)。
- 键:无序、无下标、不允许重复(唯一)。
- 值:无序、无下标、允许重复。
Map集合概述
特点:存储一对数据(Key-Value),无序、无下标,键不可重复。
方法:
V put(K key,V value)
//将对象存入到集合中,关联键值。key重复则覆盖原值。
Object get(Object key)
//根据键获取相应的值。Set<K>
//返回所有的keyCollection<V> values()
//返回包含所有值的Collection集合。Set<Map.Entry<K,V>>
//键值匹配的set集合
1 /**
2 * Map接口的使用
3 * 特点:1.存储键值对 2.键不能重复,值可以重复 3.无序
4 */
5 public class Demo01 {
6 public static void main(String[] args) {
7 //创建Map集合
8 HashMap<String, String> map = new HashMap<>();
9
10 //1.添加元素
11 map.put("cn","中国");
12 map.put("uk","英国");
13 map.put("usa","美国");
14 map.put("cn","Chinse");//相同key添加,会替换之前的value值
15 System.out.println("元素个数为:"+map.size());
16 System.out.println(map.toString());
17
18 //2.删除
19 map.remove("usa");
20 System.out.println("删除后元素个数为:"+map.size());
21 System.out.println(map.toString());
22
23 //3.遍历
24 //3.1 使用keyset(),先获取key,再使用get(key)方法获取value值
25 Set<String> keySet = map.keySet();
26 for (String key:keySet) {
27 System.out.println(key+"-----"+map.get(key));
28 }
29 //简写
30 for (String s:map.keySet()) {
31 System.out.println(s+"-----"+map.get(s));
32 }
33 //3.2 使用entrySet()方法;效率更高,把key和value都拿出来了,不需要为了value再去多做一遍查询key的操作
34 Set<Map.Entry<String, String>> entries = map.entrySet();
35 for (Map.Entry<String,String> entry:entries) {
36 System.out.println(entry.getKey()+"------"+entry.getValue());
37 }
38 //简写
39 for (Map.Entry<String,String> entry:map.entrySet()) {
40 System.out.println(entry.getKey()+"------"+entry.getValue());
41 }
42
43
44 }
45 }
keySet遍历和entrySet的区别
Map集合的实现类
HashMap【重点】
JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value。
1 /**
2 * 学生类
3 */
4 public class Student {
5 private String name;
6 private int age;
7
8 public String getName() {
9 return name;
10 }
11
12 public void setName(String name) {
13 this.name = name;
14 }
15
16 public int getAge() {
17 return age;
18 }
19
20 public void setAge(int age) {
21 this.age = age;
22 }
23
24 @Override
25 public String toString() {
26 return "Student{" +
27 "name='" + name + '\'' +
28 ", age=" + age +
29 '}';
30 }
31
32 public Student(String name, int age) {
33 this.name = name;
34 this.age = age;
35 }
36 }
1 /**
2 * HashMap的使用
3 * 存储结构:哈希表(数组+链表+红黑树)
4 */
5 public class Demo01 {
6 public static void main(String[] args) {
7 HashMap<Student, String> hashMap = new HashMap<>();
8 Student p1 = new Student("赵一",11);
9 Student p2 = new Student("王二",11);
10 Student p3 = new Student("张三",11);
11 Student p4 = new Student("李四",11);
12 //1.添加元素
13 hashMap.put(p1,"北京");
14 hashMap.put(p2,"上海");
15 hashMap.put(p3,"广州");
16 hashMap.put(p4,"曹县");
17 hashMap.put(p4,"曹县(山东)");//不能添加重复的key,但是会将value更新
18
19 //,上面已经有一个李四的key了,通过这个还可以继续添加,那能不能让系统根据key的数据判重,而不是根据内存地址?
20 hashMap.put(new Student("李四",11),"南京");
21 System.out.println("元素个数为:"+hashMap.size());
22 System.out.println(hashMap.toString());
23
24 //2.删除元素
25 hashMap.remove(p2);
26 System.out.println(hashMap.toString());
27
28 //3.遍历
29 //3.1 使用keySet遍历
30 for (Student s:hashMap.keySet()) {
31 System.out.println(s+"------"+hashMap.get(s));
32 }
33 //3.2 使用entrySet遍历
34 for (Map.Entry<Student,String> entry:hashMap.entrySet()) {
35 System.out.println(entry.getKey()+"------"+entry.getValue());
36 }
37
38 //4.判断
39 System.out.println(hashMap.containsKey(p1));
40 System.out.println(hashMap.containsKey(new Student("李四",11)));
41 System.out.println(hashMap.containsValue("曹县(山东)"));
42 }
43 }
注:和之前说过的HashSet类似,重复依据是hashCode和equals方法,重写即可:
1 @Override
2 public int hashCode() {
3 final int prime = 31;
4 int result = 1;
5 result = prime * result + id;
6 result = prime * result + ((name == null) ? 0 : name.hashCode());
7 return result;
8 }
9 @Override
10 public boolean equals(Object obj) {
11 if (this == obj)
12 return true;
13 if (obj == null)
14 return false;
15 if (getClass() != obj.getClass())
16 return false;
17 Student other = (Student) obj;
18 if (id != other.id)
19 return false;
20 if (name == null) {
21 if (other.name != null)
22 return false;
23 } else if (!name.equals(other.name))
24 return false;
25 return true;
26 }
HashMap源码分析
默认初始化容量:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
- 数组最大容量:
static final int MAXIMUM_CAPACITY = 1 << 30;
- 数组最大容量:
默认加载因子:
static final float DEFAULT_LOAD_FACTOR = 0.75f;
链表调整为红黑树的链表长度阈值(JDK1.8):
static final int TREEIFY_THRESHOLD = 8;
红黑树调整为链表的链表长度阈值(JDK1.8):
static final int UNTREEIFY_THRESHOLD = 6;
链表调整为红黑树的数组最小阈值(JDK1.8):
static final int MIN_TREEIFY_CAPACITY = 64;
HashMap存储的数组:
transient Node<K,V>[] table;
- HashMap存储的元素个数:
transient int size;
- 默认加载因子是什么?
- 就是判断数组是否扩容的一个因子。假如数组容量为100,如果HashMap的存储元素个数超过了100*0.75=75,那么就会进行扩容。
- 链表调整为红黑树的链表长度阈值是什么?
- 假设在数组中下标为3的位置已经存储了数据,当新增数据时通过哈希码得到的存储位置又是3,那么就会在该位置形成一个链表,当链表过长时就会转换成红黑树以提高执行效率,这个阈值就是链表转换成红黑树的最短链表长度;
- 红黑树调整为链表的链表长度阈值是什么?
- 当红黑树的元素个数小于该阈值时就会转换成链表。
- 链表调整为红黑树的数组最小阈值是什么?
- 并不是只要链表长度大于8就可以转换成红黑树,在前者条件成立的情况下,数组的容量必须大于等于64才会进行转换。
HashMap的数组table存储的就是一个个的Node<K,V>类型,很清晰地看到有一对键值,还有一个指向next的指针(以下只截取了部分源码):
1 static class Node<K,V> implements Map.Entry<K,V> {
2 final K key;
3 V value;
4 Node<K,V> next;
5 }
之前的代码中在new对象时调用的是HashMap的无参构造方法,进入到该构造方法的源码查看一下:
1 public HashMap() {
2 this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
3 }
发现没什么内容,只是赋值了一个默认加载因子;而在上文我们观察到源码中table和size都没有赋予初始值,说明刚创建的HashMap对象没有分配容量,并不拥有默认的16个空间大小,这样做的目的是为了节约空间,此时table为null,size为0。
当我们往对象里添加元素时调用put方法:
1 public V put(K key, V value) {
2 return putVal(hash(key), key, value, false, true);
3 }
put方法把key和value传给了putVal,同时还传入了一个hash(Key)所返回的值,这是一个产生哈希值的方法,再进入到putVal方法(部分源码):
1 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
2 boolean evict) {
3 Node<K,V>[] tab; Node<K,V> p; int n, i;
4 if ((tab = table) == null || (n = tab.length) == 0)
5 n = (tab = resize()).length;
6 if ((p = tab[i = (n - 1) & hash]) == null)
7 tab[i] = newNode(hash, key, value, null);
8 else{
9 //略
10 }
11 }
这里面创建了一个tab数组和一个Node变量p,第一个if实际是判断table是否为空,而我们现在只关注刚创建HashMap对象时的状态,此时tab和table都为空,满足条件,执行内部代码,这条代码其实就是把resize()所返回的结果赋给tab,n就是tab的长度,resize顾名思义就是重新调整大小。查看resize()源码(部分):
1 final Node<K,V>[] resize() {
2 Node<K,V>[] oldTab = table;
3 int oldCap = (oldTab == null) ? 0 : oldTab.length;
4 int oldThr = threshold;
5 if (oldCap > 0);
6 else if (oldThr > 0);
7 else { // zero initial threshold signifies using defaults
8 newCap = DEFAULT_INITIAL_CAPACITY;
9 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
10 }
11 @SuppressWarnings({"rawtypes","unchecked"})
12 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
13 table = newTab;
14 return newTab;
15 }
该方法首先把table及其长度赋值给oldTab和oldCap;threshold是阈值的意思,此时为0,所以前两个if先不管,最后else里newCap的值为默认初始化容量16;往下创建了一个newCap大小的数组并将其赋给了table,刚创建的HashMap对象就在这里获得了初始容量。然后我们再回到putVal方法,第二个if就是根据哈希码得到的tab中的一个位置是否为空,为空便直接添加元素,此时数组中无元素所以直接添加。至此HashMap对象就完成了第一个元素的添加。当添加的元素超过16*0.75=12时,就会进行扩容:
1 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict){
2 if (++size > threshold)
3 resize();
4 }
扩容的代码如下(部分):
1 final Node<K,V>[] resize() {
2 int oldCap = (oldTab == null) ? 0 : oldTab.length;
3 int newCap;
4 if (oldCap > 0) {
5 if (oldCap >= MAXIMUM_CAPACITY) {//略}
6 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
7 oldCap >= DEFAULT_INITIAL_CAPACITY)
8 }
9 }
核心部分是else if里的移位操作,也就是说每次扩容都是原来大小的两倍。
*注**:额外说明的一点是在JDK1.8以前链表是头插入,JDK1.8以后链表是尾插入。
HashSet源码分析
了解完HashMap之后,再回过头来看之前的HashSet源码,为什么放在后面写你们看一下源码就知道了(部分):
1 public class HashSet<E>
2 extends AbstractSet<E>
3 implements Set<E>, Cloneable, java.io.Serializable
4 {
5 private transient HashMap<E,Object> map;
6 private static final Object PRESENT = new Object();
7 public HashSet() {
8 map = new HashMap<>();
9 }
10 }
可以看见HashSet的存储结构就是HashMap,那它的存储方式是怎样的呢?可以看一下add方法:
1 public boolean add(E e) {
2 return map.put(e, PRESENT)==null;
3 }
很明了地发现它的add方法调用的就是map的put方法,把元素作为map的key传进去的。。
Hashtable
- JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
初始容量11,加载因子0.75。
这个集合在开发过程中已经不用了,稍微了解即可。
Properties
- Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
它继承了Hashtable的方法,与流关系密切,此处不详解。
TreeMap
- 实现了SortedMap接口(是Map的子接口),可以对key自动排序。
1 /**
2 * TreeMap的使用
3 * 存储结构:红黑树
4 */
5 public class Demo3 {
6 public static void main(String[] args) {
7 TreeMap<Student, Integer> treeMap=new TreeMap<Student, Integer>();
8 Student s1=new Student("tang", 36);
9 Student s2=new Student("yu", 101);
10 Student s3=new Student("he", 10);
11 //1.添加元素
12 treeMap.put(s1, 21);
13 treeMap.put(s2, 22);
14 treeMap.put(s3, 21);
15 //不能直接打印,需要实现Comparable接口,因为红黑树需要比较大小
16 System.out.println(treeMap.toString());
17 //2.删除元素
18 treeMap.remove(new Student("he", 10));
19 System.out.println(treeMap.toString());
20 //3.遍历
21 //3.1 使用keySet()
22 for (Student key : treeMap.keySet()) {
23 System.out.println(key+" "+treeMap.get(key));
24 }
25 //3.2 使用entrySet()
26 for (Entry<Student, Integer> entry : treeMap.entrySet()) {
27 System.out.println(entry.getKey()+" "+entry.getValue());
28 }
29 //4.判断
30 System.out.println(treeMap.containsKey(s1));
31 System.out.println(treeMap.isEmpty());
32 }
33 }
在学生类中实现Comparable接口:
1 public class Student implements Comparable<Student>{
2 @Override
3 public int compareTo(Student o) {
4 int n1=this.id-o.id;
5 return n1;
6 }
除此之外还可以使用比较器来定制比较:
1 TreeMap<Student, Integer> treeMap2=new TreeMap<Student, Integer>(new Comparator<Student>() {
2 @Override
3 public int compare(Student o1, Student o2) {
4 // 略
5 return 0;
6 }
7 });
TreeSet源码
和HashSet类似,放在TreeMap之后讲便一目了然(部分):
1 public class TreeSet<E> extends AbstractSet<E>
2 implements NavigableSet<E>, Cloneable, java.io.Serializable
3 {
4 private transient NavigableMap<E,Object> m;
5 private static final Object PRESENT = new Object();
6 TreeSet(NavigableMap<E,Object> m) {
7 this.m = m;
8 }
9 public TreeSet() {
10 this(new TreeMap<E,Object>());
11 }
12 }
TreeSet的存储结构实际上就是TreeMap,再来看其存储方式:
1 public boolean add(E e) {
2 return m.put(e, PRESENT)==null;
3 }
它的add方法调用的就是TreeMap的put方法,将元素作为key传入到存储结构中。
Collections工具类
概念:集合工具类,定义了除了存取以外的集合常用方法。
方法:
public static void reverse(List<?> list)
//反转集合中元素的顺序public static void shuffle(List<?> list)
//随机重置集合元素的顺序public static void sort(List<T> list)
//升序排序(元素类型必须实现Comparable接口)
1 /**
2 * 演示Collections工具类的使用
3 *
4 */
5 public class Demo4 {
6 public static void main(String[] args) {
7 List<Integer> list=new ArrayList<Integer>();
8 list.add(20);
9 list.add(10);
10 list.add(30);
11 list.add(90);
12 list.add(70);
13
14 //sort排序
15 System.out.println(list.toString());
16 Collections.sort(list);
17 System.out.println(list.toString());
18 System.out.println("---------");
19
20 //binarySearch二分查找
21 int i=Collections.binarySearch(list, 10);
22 System.out.println(i);
23
24 //copy复制
25 List<Integer> list2=new ArrayList<Integer>();
26 for(int i1=0;i1<5;++i1) {
27 list2.add(0);
28 }
29 //该方法要求目标元素容量大于等于源目标
30 Collections.copy(list2, list);
31 System.out.println(list2.toString());
32
33 //reserve反转
34 Collections.reverse(list2);
35 System.out.println(list2.toString());
36
37 //shuffle 打乱
38 Collections.shuffle(list2);
39 System.out.println(list2.toString());
40
41 //补充:list转成数组
42 Integer[] arr=list.toArray(new Integer[0]);
43 System.out.println(arr.length);
44 //补充:数组转成集合
45 String[] nameStrings= {"tang","he","yu"};
46 //受限集合,不能添加和删除
47 List<String> list3=Arrays.asList(nameStrings);
48 System.out.println(list3);
49
50 //注:基本类型转成集合时需要修改为包装类
51 }
52 }
Java集合 - 集合知识点总结概述的更多相关文章
- 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合
不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...
- Java 集合常见知识点&面试题总结(上),2022 最新版!
你好,我是 Guide.秋招即将到来(提前批已经开始),我对 JavaGuide 的内容进行了重构完善,公众号同步一下最新更新,希望能够帮助你. 你也可以在网站(javaguide.cn)上在线阅读, ...
- Java基础知识强化之集合框架笔记16:List集合的特有功能概述和测试
1. List集合的特有功能概述: (1)添加功能: void add(int index, Object element):在指定位置添加元素 (2)获取功能: Object get(int ind ...
- 牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现
不多说,直接上干货! 先来看个泛型概念提出的背景的例子. GenericDemo.java package zhouls.bigdata.DataFeatureSelection; import ja ...
- Java中集合的概述
一.集合和数组的区别 1.数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用. 2.集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数 ...
- Java面试集合(三)
前言 大家好,给大家带来Java面试集合(三)的概述,希望你们喜欢 三 1.在Java中是否可以含有多个类? 答:可以含有多个类,但只有一个是public类,public类的类名与文件名必须一致. 2 ...
- Java面试集合(二)
前言 大家好,给大家带来Java面试集合(二)的概述,希望你们喜欢 二 1.请问线程有哪些状态? 新建状态(New) 就绪状态(Runnable) 运行状态(Running) 阻塞状态(Blocked ...
- Java面试集合(一)
前言 大家好,给大家带来Java面试集合(一)的概述,希望你们喜欢 一 1.Java按应用范围可划分几个版本? 答:Java按应用范围有三个版本,分别是JavaSE,JavaEE,JavaME. 2. ...
- Java面试集合(三)-30道面试题
前言 大家好,我是 Vic,今天给大家带来Java面试集合(三)的概述,希望你们喜欢 三 1.在Java中是否可以含有多个类?答:可以含有多个类,但只有一个是public类,public类的类名与文件 ...
- Java之集合初探(一)
一.集合概述.区别 集合是一种容器,数组也是一种容器 在Java编程中,装各种各样的对象(引用类型)的叫做容器. 为什么出现集合类? 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的 ...
随机推荐
- Nginx优化与防盗链
目录: 一.隐藏版本号 二.修改用户与组 三.缓存时间 四.日志切割 五.连接超时 六.更改进程数 七.配置网页压缩 一.隐藏版本号 可以使用 Fiddler 工具抓取数据包,查看 Nginx版本 也 ...
- crontab 语法和最快速的学习
1.Cron 时间表语法 # ┌───────────── 分钟 (0 - 59) # │ ┌───────────── 小时 (0 - 23) # │ │ ┌───────────── 月的某天 ( ...
- ansible 批量安装yum包
1.首先安装一下ansible yum install ansible 2.修改一下ansible的参数以防ssh过去的时候需要首次判断yes 或者no sed -i 's/#host_key_ch ...
- 安卓gradle时报错"ERROR: Plugin with id 'com.android.application' not found."
在build.gradle中更改gradle插件版本号 buildscript { repositories { google() jcenter() } dependencies { //版本号请根 ...
- RestFul的认识与详解
RestFul :是一种软件架构风格,设计风格,而不是标准.提供了一组设计原则和约束条件. 简单概述: REST -- REpresentational State Transfer 直接翻译:表现层 ...
- 新环境c7、php7.4、openssl1.1.1g,再discuz里发送邮件总是报ssl连接不上
Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:1416F086:SSL r ...
- springBoot 基础入门
来处:是spring项目中的一个子项目 优点 (被称为搭建项目的脚手架) 减少一切xml配置,做到开箱即用,快速上手,专注于业务而非配置 从创建项目上: -- 快速创建独立运 ...
- 简述编写Django应用的基本步骤
(1)创建项目,cd到一个你想要放置你代码的目录.Django -admin startproject mysite. Django project即一个Django项目实例需要的设置项的集合,包括数 ...
- P3706-[SDOI2017]硬币游戏【高斯消元,字符串hash】
正题 题目链接:https://www.luogu.com.cn/problem/P3706 题目大意 给出 \(n\) 个长度为 \(m\) 的 \(H/T\) 串. 开始一个空序列,每次随机在后面 ...
- P7854-「EZEC-9」GCD Tree【构造】
正题 题目连接:https://www.luogu.com.cn/problem/P7854 题目大意 给出\(n\)数字的一个序列\(a\). 现在要求构造一棵树,使得对于任意的\((x,y)\)都 ...