1.集合框架-数组的特点、弊端与集合框架体系介绍

1.集合与数组存储数据概述:

集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)

2.数组存储的特点:

一旦初始化以后,其长度就确定了。
数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。比如

1
String[] arr;int[] arr1;Object[] arr2;

3.数组存储的弊端:

1 一旦初始化以后,其长度就不可修改
2 数组中提供的方法非常限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
3 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
4 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

4.集合存储的优点:

解决数组存储数据方面的弊端。

5.概览

|—-Collection接口:单列集合,用来存储一个一个的对象
|—-List接口:存储有序的、可重复的数据。 –>“动态”数组
|----ArrayList、LinkedList、Vector
|—-Set接口:存储无序的、不可重复的数据 –>一般意义的“集合”
|—-HashSet、LinkedHashSet、TreeSet
java.util.Map:存储一对一对的数据
|—-Map接口:存储无序的、不可重复的数据
|—-HashMap、LinkedHashMap、TreeMap,Hashtable,Properties

2.集合框架-Collection 接口中的方法测试

1.单列集合框架结构

|—-Collection接口:单列集合,用来存储一个一个的对象
|—-List接口:存储有序的、可重复的数据。 –>“动态”数组
|—-ArrayList、LinkedList、Vector
|—-Set接口:存储无序的、不可重复的数据 –>高中讲的“集合”
|—-HashSet、LinkedHashSet、TreeSet
对应图示:

image.png

2.Collection接口常用方法:

add(Object obj),
addAll(Collection coll),
size(),
isEmpty(),
clear();
contains(Object obj),
containsAll(Collection coll),
remove(Object obj),
removeAll(Collection coll),
retainsAll(Collection coll), //求两个集合的交集
equals(Object obj);
hasCode(),
toArray(),
iterator();

没有get()和set()方法

3.Collection集合与数组间的转换

集合 —>数组:toArray()

1
2
3
4
Object[] arr = `coll.toArray();`
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}

拓展:数组 —>集合:调用Arrays类的静态方法asList(T … t)

Arrays.asList();返回的是一个固定大小的列表,不能进行添加操作

1
2
3
4
5
6
7
8
9
10
11
List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});

//返回的是一个固定大小的列表,不能进行添加操作`。System.out.println(list);
Arrays.asList(new int[]{123, 456});

List arr1 = Arrays.asList(new int[]{123, 456});
System.out.println(arr1.size());//1 ,当里面只有一个一维数组

List arr2 = Arrays.asList(new Integer[]{123, 456});
System.out.println(arr2.size());//2

Arrays.asList(new int[]{123, 456}) 创建了一个包含 一个 数组 ( int[] )List这个 List 的大小是 1,因为 List 只有一个元素,就是这个 int[] 数组。

arr1 实际上只是一个包装了底层 int[] 数组的 List,它不包含 123456 这两个整数,而是包含 int[] 数组的引用。

4. 使用Collection集合存储对象的要求

向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().(因为collection中的相关方法contains()/remove()需要重写)

5. 集合的遍历

再list类中讲

6. 章节要求

①选择合适的集合类去实现数据的保存,调用其内部的相关方法。

下面内容暂不要求

②不同的集合类底层的数据结构为何?
③如何实现数据的操作的(增删改查等)。

3.集合框架-List 接口常用方法的测试

1 常用方法

增:add(Object obj)
删:remove(int index) / remove(Object obj)
改:set(int index, Object ele) 查:get(int index)
插:add(int index, Object ele)
长度:size()

2 遍历

Iterator迭代器方式-Collection集合的专用遍历方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args) {

//创建集合对象
Collection<String> c = new ArrayList<>();

//添加元素
c.add("hello");
c.add("world");
c.add("java");
c.add("javaee");

//Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
Iterator<String> it = c.iterator();

//用while循环改进元素的判断和获取
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}

增强for循环-JDK5之后出现的,其内部原理是一个Iterator迭代器,实现Iterable接口的类才可以使用迭代器和增强for循环

注意:增强for循环内部不能直接操作集合的元素,只推荐做遍历使用

增强型 for 循环内部隐式地使用了一个迭代器来遍历集合。当您在循环内部修改集合时,可能会使迭代器失效,导致后续的遍历操作出现错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");

//1,数据类型一定是集合或者数组中元素的类型
//2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素
//3,list就是要遍历的集合或者数组
for(String str : list){
System.out.println(str);
}
}

③ 普通for循环

4.集合框架-List 不同实现类的对比

​ |—-ArrayList:作为List接口的主要实现类;线程不安全的,效率高,遇到线程安全问题用collections自己包一下

1
List<String> threadSafeList = Collections.synchronizedList(arrayList);

​ |—-LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
​ |—-Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储 彻底失宠,已经不用了

5.List的线程安全问题

使用Collections.synchronizedList方法包装成线程安全的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
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.*;

public class ThreadSafeCollectionExample {
public static void main(String[] args) {

// 创建一个非线程安全的ArrayList
List<Integer> list = new ArrayList<>();

// 使用Collections.synchronizedList方法包装成线程安全的ArrayList
List<Integer> synchronizedList = Collections.synchronizedList(list);

// 创建多个线程,并发地向synchronizedList中添加元素
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
synchronizedList.add(i);
}
};

// 创建多个线程,并发地执行任务
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(task);
threads.add(thread);
thread.start();
}

// 等待所有线程执行完毕
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

// 打印线程安全的ArrayList的大小
System.out.println(synchronizedList.size()); // 应该为10000
}
}

[面试题]
面试题:ArrayList、LinkedList、Vector者的异同?
同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据
不同:上面说过,自行回忆

6.集合框架-Set 不同实现类的对比及 Set 无序性、不可重复性的剖析

1.存储的数据特点:无序、不可重复

以HashSet为例进行说明

1 无序性:不等于随机性。存储的数据在底层中不是依次排列的,表现为无序性`
2 不可重复性:保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一个。

2.元素添加过程:(以HashSet为例)

我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置)

判断数组此位置上是否已经有元素:
如果此位置上没其他元素,则元素a添加成功。 —>情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素,则比较元素a与元素b的hash值:
如果hash值不相同,则元素a添加成功。—>情况2
如果hash值相同,进而需要调用元素a所在类的equals()方法:
equals()返回true,元素a添加失败
equals()返回false,则元素a添加成功。—>情况3

对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。

为啥不是覆盖?

避免覆盖错误: 如果直接覆盖,当两个键的哈希值相同但它们不是同一个键时,可能会导致数据丢失或错误。

jdk 7 :元素a放到数组中,指向原来的元素。 jdk 8 :原来的元素在数组中,指向元素a
总结:七上八下

3.常用实现类:

​ |—-Set接口:存储无序的、不可重复的数据
​ |—-HashSet:作为Set接口的主要实现类;底层用HashMap,即使用数组+单向链表+红黑树结构进行存储,
​ |—-LinkedHashSet:作为HashSet的子类;在现有基础上,又添加了一组双向链表,用于记录添加元素的先后顺序
​ |—-TreeSet:底层用红黑树存储,可以按照添加的元素的指定的属性的大小顺序进行遍历

4.常用方法

Set接口中没额外定义新的方法,使用的都是Collection中声明过的方法。

Set 接口的特性:

  • 无序性: Set 接口中的元素是无序的,因此没有索引的概念,无法使用 get(index) 来获取特定位置的元素。
  • 唯一性: Set 接口中的元素必须是唯一的,因此不能通过 update() 方法修改元素的值。

5.set中无序性,不可重复性的理解的要求:

1. 无序性不等于随机性

​ 添加元素的顺序和遍历元素的顺序不一致,是不是就是无序性呢?no!什么是无序性?与添加元素的位置有关,在内存中不是依次排列的,表现为无序性(LinkedHashSet也是无序,不过用了链表指向顺序)

2. 不可重复性

​ 添加到Set的元素是不能相同的,比较的标准:需要判断hashCode()得到的哈希值、equals()得到的boolean型结果,哈希值相同且equals()返回true,则认为元素是相同的。

6.添加到hashset/linkedhashset中元素的要求:

​ 要求元素所在的类要重写两个方法: equals()和hashCode()。
​ 同时,要求equals()和 hashCode()要保持一致性!我们只需要在IDEA中自动生成两个方法的重写即可

7.集合框架-TreeSet 的使用

1.向TreeSet中添加元素的要求

要求是相同类型的对象,否则报异常。

2.判断数据是否相同的标准

TreeSet 使用红黑树数据结构来存储元素,红黑树是一种自平衡的二叉查找树,它通过比较元素的大小来确定元素在树中的位置,因此TreeSet中的元素所在的内不需要重写hashCode()和equal方法替换成看Comparable或Comparator返回的结果

8.集合框架-Map不同实现类的对比与 HashMap 中元素的特点

双列集合框架:Map

1.常用实现类结构

|—-Map:双列数据,存储key-value对的数据 —类似于高中的函数:y = f(x)
|—-HashMap:作为Map的主要实现类;线程不安全的,效率高;能存储null的key和value
|—-LinkedHashMap:保证在遍历map元素时,可以照添加的顺序实现遍历。
|—-Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value
|—-TreeMap:线程不安全的,保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序,底层使用红黑树
|—-Properties:常用来处理配置文件。key和value都是String类型
HashMap的底层: 数组+链表 (jdk7及之前)
数组+链表+红黑树 (jdk 8)

2.存储结构的理解:

Map中的key:无序的、不可重复的,使用Set存储所有的key —> key所在的类要重写equals()和hashCode() (以HashMap为例)
Map中的value:无序的、可重复的,使用Collection存储所有的value
一个键值对:key-value构成了一个Entry对象。
Map中的entry:无序的、不可重复的,使用Set存储所有的entry

9.集合框架-Map 接口常用方法的测试

添加:put(Object key,Object value)
删除:remove(Object key)
修改:put(Object key,Object value)
查询:get(Object key)
长度:size()
遍历:keySet() / values() / entrySet()

10.集合框架-TreeMap、Properties 的使用

1.TreeMap的使用

向TreeMap中添加key-value,要求key必须是由同一个类创建的对象,因为要按照key进行排序:自然排序 、定制排序

2.使用Properties读取配置文件

Properties:常用来处理配置文件。key和value都是String类型

Properties常用作配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String[] args)  {
FileInputStream fis = null;
try {
Properties pros = new Properties();
fis = new FileInputStream("jdbc.properties");
pros.load(fis);//加载流对应的文件
String name = pros.getProperty("name");
String password = pros.getProperty("password");
System.out.println("name = " + name + ", password = " + password);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

11.集合框架-Collections 工具类的使用

Collections工具类

1.作用:操作Collection和Map的工具类

区分collection 和collections

2.常用方法:

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 对象的所旧值

说明:ArrayList和HashMap都是线程不安全的,如果程序要求线程安全,我们可以将ArrayList、HashMap转换为线程安全的。
使用synchronizedList(List list) 和 synchronizedMap(Map map)

3.面试题:

面试题:Collection 和 Collections的区别?

Collections是工具类