Fork me on GitHub

Java_day8

自用Java笔记(Ⅷ),主要记录Java集合!奋斗ing

集合

概述

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

数组在存储多个数据方面的特点(缺点*):

  • (*)一旦初始化后,长度就确定了
  • 一旦定义好,元素的类型也确定了
  • (*)提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高
  • (*)获取数组中实际元素的个数的需求,没有现成的属性或方法可用
  • (*)存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足

Java集合 可以分为CollectionMap两种体系(接口)

  • Collection接口:单列数据,定义了存取一些对象的方法的集合
    • List:元素有序、可重复的集合,“动态数组”
    • Set:元素无序、不可重复的集合,“数学上的集合”
  • Map接口:双列数据,保存具有映射关系”key-value对”的集合,“数学上的函数映射”

集合框架

1
2
3
4
5
6
7
8
9
|----Collection接口:单列集合,用来存储一个一个的对象
|----List接口:存储有序的、可重复的数据 --> “动态”数组
|----ArrayList、LinkedList、Vector

|----Set接口:存储无序的、不可重复的数据 --> 数学中的“集合”
|----HashSet、LinkedHashSet、TreeSet

|----Map接口:双列接口,用来存储一对(key-value)数据 --> y = f(x)
|----HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

Collection常用方法(通用)

  • add(Object e): 将元素e添加到集合coll中
  • addAll(Collection coll1): 将coll1集合中的元素添加到当前的集合中
  • size(): 获取添加的元素的个数
  • clear(): 清空集合元素
  • isEmpty(): 判断当前集合是否为空
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
@Test
public void test1(){
Collection coll = new ArrayList();

//add(Object e): 将元素e添加到集合coll中、
coll.add("AA");
coll.add("BB");
coll.add(123); //自动装箱
coll.add(new Date());

//size(): 获取添加的元素的个数
System.out.println(coll.size());//4

//addAll(Collection coll1): 将coll1集合中的元素添加到当前的集合中
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.add("cc");
coll.addAll(coll1);

System.out.println(coll.size());//6
System.out.println(coll);//[AA, BB, 123, Thu Oct 31 12:03:02 CST 2019, 456, cc]

//clear(): 清空集合元素
coll.clear();

//isEmpty(): 判断当前集合是否为空
System.out.println(coll.isEmpty());//true
}
  • contains(Object obj): 判断当前集合中是否包含obj

PS:向Collection接口的实现类的对象中 添加数据obj时,要求obj所在类要重写equals()。不是判断地址,判断内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void test2(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
Person p = new Person("Jerry1", 20);
coll.add(p);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);

//1.contains(Object obj): 判断当前集合中是否包含obj
//我们在判断时会调用obj对象所在类的equals()
boolean contains = coll.contains(123);
System.out.println(contains);//true
System.out.println(coll.contains(new String("Tom")));//true

System.out.println(coll.contains(new Person("Jerry", 20)));//false
System.out.println(coll.contains(p));//true
//PS:向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()。
}
  • containsAll(Collection coll1): 判断形参coll1中的所有元素都存在于当前集合中。
1
2
3
//2.containsAll(Collection coll1): 判断形参coll1中的所有元素都存在于当前集合中。
Collection coll1 = Arrays.asList(123,4567);
System.out.println(coll.containsAll(coll1));//false
  • remove(Object obj): 从当前集合中移除obj元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test3(){
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);

//3.remove(Object obj): 从当前集合中移除obj元素
coll.remove(123);
System.out.println(coll);
//[456, com.good.java.Person@4ee285c6, Tom, false]
coll.remove(new Person("Jerry", 20));
System.out.println(coll);
//[456, com.good.java.Person@4ee285c6, Tom, false]
}
  • removeAll(Collection coll1): 差集,从当前集合中移除coll1中所有的元素
1
2
3
4
5
//4.removeAll(Collection coll1): 差集,从当前集合中移除coll1中所有的元素
Collection coll1 = Arrays.asList(123,456);
coll.removeAll(coll1);
System.out.println(coll);
//[com.good.java.Person@4ee285c6, Tom, false]
  • retainAll(Collection coll1): 交集,获取当前集合和coll1集合的交集
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void test4() {
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);

//5.retainAll(Collection coll1): 交集,获取当前集合和coll1集合的交集
Collection coll1 = Arrays.asList(123,456,789);
coll.retainAll(coll1);
System.out.println(coll);
//[123, 456]
}
  • equals(Object obj)
1
2
3
4
5
6
7
8
9
    Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add(456);
// coll1.add(new Person("Jerry", 20));
coll1.add(new String("Tom"));
coll1.add(false);

//6.equals(Object obj)
System.out.println(coll.equals(coll1));
  • hashCode(): 返回当前对象的哈希值
1
2
3
4
5
6
7
8
9
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person("Jerry", 20));
coll.add(new String("Tom"));
coll.add(false);

//7.hashCode(): 返回当前对象的哈希值
System.out.println(coll.hashCode());//701070075
  • 集合 —> 数组:toArray()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Object[] arr = coll.toArray();
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}

//拓展:数组 ---> 集合: 调用Arrays类的静态方法asList()
List<String> list = Arrays.asList(new String[]{"aa","bb","cc"});
System.out.println(list);//[aa, bb, cc]

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
  • iterator() 返回Iterator接口的实例,用于遍历集合元素,注意是一次性的

集合元素的遍历(迭代器接口Iterator)

  • 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
@Test
public void test1(){
Collection coll = new ArrayList();
coll.add("aa");
coll.add("BB");
coll.add(123); //自动装箱
coll.add(new Date());
Iterator iterator = coll.iterator();

//方式一:
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
//报异常NoSuchElementException
// System.out.println(iterator.next());

//方式二: 不推荐
// for (int i = 0; i < coll.size(); i++) {
// System.out.println(iterator.next());
// }

//方式三: 推荐
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
  • remove() 删除集合中某数据(调用前需要先next())
1
2
3
4
5
6
while (iterator.hasNext()) {
Object obj = iterator.next();
if ("BB".equals(obj)) {
iterator.remove();
}
}

foreach 循环遍历集合

JDK5 新增了foreach 用于遍历数组和集合(内部任然调用迭代器)

  • for(集合元素类型 局部变量:集合对象)
1
2
3
4
for (Object obj : coll) {
System.out.println(obj);
}
// 注意是局部变量,不会改变

List接口

替代数组,元素有序,且可重复

具体实现类:ArrayList、LinkedList、Vector

三者异同:

  • 同:三个类都实现了List接口,存储数据的特点相同,元素有序,且可重复

  • 异:

    ArrayList 作为List接口的主要实现类 ,线程不安全,效率高,底层用Object[]存储

    LinkedList 底层用双向链表存储,对于频繁插入、删除操作,此类效率高

    Vector 作为List的古老实现类,线程安全,效率低,底层用Object[]存储

Arraylist,的源码分析:JDK7情况下
ArrayList list= new ArrayList(/(底层创建了长度是10850bc数 HelementData List. add (123); //eLementData【0】= new Integer(123); List.0(1):/0果此次的添加导致底层 eLementDat数组容量不够,则扩容默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中结论:建议开发中使用带参的构造器:ArrayList List= new Arraylist( unt capacity)

JDK8中 ArrayList的变化:
ArrayList list= new ArrayList()/)底层0 bject】 elementdata初始化为},并没有创建List.0d(123);//第次调用d()时,底层才创建了长度10的数组,并将数据123添加到 elemen后续的添加和扩容操作与jR7无异

总结:JDK7中的 Arraylist的对象的创建类似于单例的汉式,而8中的ryst的对象的创建类似于单例的像汉式,延迟了数组的创建,节省内存

List中的常用方法

  • void add (int index, Object ele):在 index位置插入eLle元素
  • boolean addAll (int index, Collection eles):从 index位置开始特eles中的所有元素添加进来
  • Object get ( int index):获取指定 index位置的元素
  • int indexOf (Object obj):返园obj在集合中首次出现的位置
  • int lastIndexOf (Object obj):返bj在当前集台中末次出现的位置
  • Object remove ( int index):移除指定inex位置的元素,并返回此元素。(区别于Collection的,eg:List. remove(2); list.remove(new Integer (2);)
  • Object set ( int index, Object ele):设置指定 index位置的元素为ele
  • List subList ( int fromIndex, int toIndex):返从 fromIndex到 toIndex位置的子集合

总结:常用方法

  • 增:add(Object obj)
  • 删:remove(int index) / remove(object obj)
  • 改: set(int index, Object ele)
  • 查:get(int index)
  • 插:add(int index, Object ele)
  • 长度:size()
  • 遍历:①Iterate送代器 ②增强for循环 ③普通的循环

Set接口

存储无序的、不可重复的数据 –> 数学中的“集合”
|—-HashSet、LinkedHashSet、TreeSet

  • 无序性:不等于随机性,添加的位置不同
  • 不可重复性:保证添加的元素按照equals()判断时,不能返回true

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

要求:

  • 向Set中添加的数据,其所在类一定要重写hashCode() 和 equals()
  • 重写的方法必须保持一致性,相同的对象必须具有相等的散列码。(技巧:对象中用作equals方法比较的Field,都应该用来计算hashCode值)

HashSet: 作为set接口的主要实现类;线程不安全的;可以存储null值

LinkedHashSet: 作为HashSet的子类,遍历内部数据时,可以按照添加的顺序遍历(原因:在添加数据的同时,每个数据还维护了俩应用,记录此数据前一个数据和后一个数据的地址)优点:对于频繁的遍历操作效率更高。

TreeSet可以按照添加对象的指定属性,进行排序

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
@Test
public void test2(){
//HashSet
Set set = new HashSet();
set.add(123);
set.add("AA");
set.add(false);

Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// AA
// false
// 123
//LinkedHashSet
LinkedHashSet linkedHashSet = new LinkedHashSet();
linkedHashSet.add(123);
linkedHashSet.add("AA");
linkedHashSet.add(false);

Iterator iterator1 = linkedHashSet.iterator();
while (iterator1.hasNext()) {
System.out.println(iterator1.next());
}
// 123
// AA
// false
}

TreeSet:向其中添加数据,要求是相同的对象。比较是否添加的对象相同,此处不使用equals,可以分别实现Comparable和Comparator实现自然和定制排序。

  • 自然排序使用的是compareTo返回0,必须重写compareTo
  • 定制排序使用的是compare返回0,必须重写compare
1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test2(){
TreeSet set = new TreeSet();
set.add(123);
set.add(34);
set.add(577);

Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}

Map接口

双列接口,用来存储一对(key-value)数据 –> y = f(x)

|—-HashMap :作为Map的主要实现类;线程不安全,效率高,能存储null 的key 和value,底层:数组+链表(JDK7)+红黑树(JDK8)
|—-LinkedHashMap :保证在遍历map元素时,可以按照添加的顺序实现遍历,对于频繁的遍历操作,此类执行效率高于HashMap
|—-TreeMap : 保证按照添加的 key-value对 进行排序,实现排序遍历,按照key自然排序或定制排序,底层使用红黑树。
|—-Hashtable : 作为古老的实现类,线程安全,效率低,不能存储null 的key 和value
|—-Properties : 常用来处理配置文件,key和value都是String类型

Map结构的理解:

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

HashMap的底层实现原理

HashMap的底层实现原理?d7为例说明HashMap map new HashMap():
在实例化以后,底层创建了长度是16的一维数组 Entry【 table
..可能已经执行过多次put map. put(key1, vaLue1)
首先,调用key1所在类的 hashcode()计算key1哈希值,此哈希信经过某种算法计算以后,得到在 Entry数组中的存放位置。
如果此位置上的数据为空,此时的ey1- value1添加成功情况如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在),比较key1和已经存在的一个或多个数据的哈希值:
如果Rey1的哈希值与已经存在的数据的哈希值都不相同,此的key1- value1添加成功。—)况2如果Rey1的哈希值和已经存在的某一个数据(Rey2-vaue2)的哈希值相同,继续比较:调用key1所在类的 equals(key2如果 equals()返aLse:此的key1-vae1添加成功。—情况3如果 equaLs()返回true:使用vLue1营换 value2补充:关于情况2和情况3:此的key1- value1和原来的数据以链表的方式存储

在不断的添加过程中,会涉及到扩容问题,默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来

jdk8相较于jdk7在底层实现方面的不同1. new Hash№p():底层没有创建一个长度为6的数组
2.j如k8底层的数组是:Mode【】,非 Entry【
3.营次调用put()方法的,底层创建长度为16的数组4.jk7底居结构只有:数组+链表。dR8中底居结构:数组+链表+红黑树当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组的长度>64的此时此索引位置上的所有数据改为体用红黑树存储。

Map接口的常用方法

添加、删除、修改操作

  • Object put(Object key, Object value):将指定key-value添加到或修改)当前map对象中

  • void putALL(Map m):将m中的所有key-value对存放到当前map中

  • Object remove(Object key):移除指定key的key- value对,并返value

  • void clear():清空当前map中的所有数据

元素查询的操作:

  • Object get(Object key):获取指定key对应的value

  • boolean containsKey (Object key):是否包含指定的key

  • boolean containsValue(Object value):是否包含指定的value

  • int size():返回map中 key- value对的个数

  • boolean isEmpty():判断当前map是否为空

  • booLean equals(Object obj):判断当前map和参数对象obj是否相等

元视图操作的方法:

  • Set keySet():返回所有key构成的Set集合

  • Collection values():返园所有 value构成的 Collection集合

  • Set entrySet():返园所有key-value对构成的Set集台

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
@Test 
public void test5(){
Map map = new HashMap();
map.put("AA"123);
map.put(45,123);
map.put("BB"56);
//遍历所有的key集:keySet()
Set set = map.keySet();
Iterator iterator = set.iterator();
While(iterator.hasNext()) {
System.out.println(iterator,next());
}
//遍历所有的value集:values()
Collection values = map.values();
for(object obj : values) {
System.out.println(obj);
}
//遍历所有的key-value
//方式一 entrySet()
Set entrySet = map.entrySet();
Iterator iterator1 = entrySet.iterator();
While(iterator1.hasNext()) {
Object obj = iterator1.next();
//entrySet:集合中的元素都是entry
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "----" + entry.getValue());
}
//方式二:
Set keySet = map.keySet();
Iterator iterator2 = keySet.iterator();
While(iterator2.hasNext()){
object key = iterator2.next();
Object value = map.get(key);
System.out.println(key + "=====" + value);
}
}

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

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

1
2
3
4
5
6
7
8
9
// Properties:常用来处理配置文件。key和value都是 String类型
public static void main(String[] args) throws Exception {
Properties pros = new Properties();
FileInputstream fis = new FileInputstream(jdbc.properties);
pros.load(fis); //加载流对应的文件
String name = pros.getProperty("name");
String password = pros.getProperty("password1");
System.out.println("name =" + name + "password =" password);
}

Collections工具类

操作Set、List和Map等集合的工具类

● Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法。

排序操作:(均为 static方法)

  • 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对象的所有旧值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test2{
List list = new ArrayList();
list.add(123);
list.add(43);
list.add(765);
list.add(-97);
// 报异常:IndexOutOfBounds Exception(" Source does not fit in dest")
// List dest = new ArrayList;
// Collections.copy(dest, List);
// 正确的:
List dest = Arrays.asList(new Object(list.size());
System.out.println(dest.size());
// List.sizeof
Collections.copy(dest, list);
System.out.println(dest);
}

Collections类中提供了多个synchronizedXxx()方法,该方法可使将指定集合包装成 线程同步 的集合,从而可以解决多线程并发访问集合时的线程安全。

-------------本文结束goodwell感谢您的阅读-------------
小二,上酒~
undefined