集合

集合继承体系

img

Collection接口: 单列集合,用来存储一个一个的对象

Map接口:双列集合,用来存储一-对(key - volue) 一对的数据

集合与数组区别

集合、数组都是对多个数据进行存储操作的结构,简称Java容器。

说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(. txt,.jpg,.avi,数据库中)

数组

数组存储的特点

一旦初始化以后,其长度就确定了

数组一-旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。

比如: String[] arr;int[] arr1;object[] arr2;

数组存储的弊端:

一旦初始化以后, 其长度就不可修改。

数组中提供的方法非常限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。

获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用

数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

集合

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

初始化集合

add

1
2
3
4
5
List<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("PHP");
languages.add("Python");
System.out.println(languages);

Arrays 工具类

1
2
List<String> jdks = Arrays.asList("JDK6", "JDK8", "JDK10");
System.out.println(jdks);

上面的 asList 是 Arrays 的静态方法,这里使用了静态导入。这种方式添加的是不可变的 List, 即不能添加、删除等操作

如果要可变,那就使用 ArrayList 再包装一下,如下面所示。

1
2
3
List<String> numbers = new ArrayList<>(Arrays.asList("1", "2", "3"));
numbers.add("4");
System.out.println(numbers);

集合通用方法

==向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要 重写equals().==

存储有序的、可重复的数据

1
2
3
4
5
6
7
@Test
public void test1(){
Collection arrayList = new ArrayList();
arrayList.add(123);//int
arrayList.add(new String("Huiex"));//String
arrayList.add(false);//布尔
arrayList.add(new Person("胖子君",19));//对象

查找

contains 查重

contains(object obj)判断当前集合中是否包含obj 返回true/false

1
2
3
4
5
6
7
8
9
10
11
   arrayList.contains(123);//true
arrayList.contains("Huiex");//true
arrayList.contains(false);//true

arrayList.contains(new Person("胖子君",19));
//false --->当重写Person中的equals方法后为ture
//contains在判断时 会调用obj对象所在类的equals方法
//所以 向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要 重写equals().

arrayList.contains(456);//false

containsAll 查重所有

contains(object obj)判断 形参集合中的所有元素 是否都存在于当前集合中

1
2
3
4
//      2.  containsAll(Collection coll1): 判断 形参集合中的所有元素 是否都存在于当前集合中
Collection arrayList1 = Arrays.asList(123,"Huiex");
System.out.println(arrayList.containsAll(arrayList1));
}

删除

remove 删除

remove(Object obj): 从当前集合中移除obj元素

1
System.out.println(arrayList.remove(123));//移除成功返回true

removeAll 删除所有

removeALL(Collection colL1):从当前集 合中移除arrayList1中所有的元素

1
2
Collection arrayList1 = Arrays.asList(123,"Huiex");
System.out.println(arrayList.removeAll(arrayList1));

交集

retainAll 交集

retainAll(Collection coll1):交集:获取当前集合和arrayList2集合的交集,并返回给当前集合

1
2
3
4
Collection arrayList2 = Arrays.asList(123,"Huiex",456);

arrayList.retainAll(arrayList2);//true
System.out.println(arrayList);// [123, Huiex]

比较

equals(0bject obj): 比较两个集合是否相等

原理是依次将集合中元素进行单个比较(contains)方法

主要有序比较,所以集合即便元素相同,但顺序不同仍 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test3(){

Collection arrayList1 = new ArrayList();
arrayList1.add(123);//int
arrayList1.add(new String("Huiex"));//String
arrayList1.add(false);//布尔
arrayList1.add(new Person("胖子君",19));//对象

Collection arrayList2 = new ArrayList();
arrayList2.add(123);//int
arrayList2.add(new String("Huiex"));//String
arrayList2.add(false);//布尔
arrayList2.add(new Person("胖子君",19));//对象

arrayList1.equals(arrayList2);//true
}

Collections工具类

Collections是一个操作Set、List 和Map等集合的工具类

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

顺序

  • 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(L ist 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
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class CollectionsTest {
@Test
public void test(){
ArrayList list = new ArrayList();
list.add(1);
list.add(5);
list.add(3);
list.add(2);
list.add(4);

// ArrayList dest = new ArrayList();
// Collections.copy(dest,list);
// 报异常: IndexOutOfBoundsException( "Source does not fit in dest ")
//因为copy需要dest集合的size小于list的size

List dest = Arrays.asList(new Object[list.size()]);
Collections.copy(dest,list);
System.out.println(dest);


Collections.reverse(list);//更改了list本身
System.out.println(list);//[4, 2, 3, 5, 1]

Collections.swap(list,0,1);
System.out.println(list);//[2, 4, 3, 5, 1]

Collections.shuffle(list);//更改了list本身
System.out.println(list);//[2, 1, 3, 5, 4]

}
}

集合和数组转化

将集合转化为数组

调用Arrays.类的静态方法toArray 该方法只支持包装类,无法转化为int型

1
2
// 使用泛型,无需显式类型转换
String[] array = list.toArray(new String[list.size()]);
1
String[] arr = set.toArray(new String[set.size()]);

使用循环

1
2
3
4
int[] d = new int[list.size()];
for(int i = 0;i<list.size();i++){
d[i] = list.get(i);
}

使用流

1
int[] arr1 = list.stream().mapToInt(i -> i).toArray();

.stream() 将list转化为流,
.mapToInt(i -> i) mapToObj可以为流中的每个元素返回一个Int流 这里是将Integer对象流转化为int流
.toArray() 将流中的元素返回到一个数组中去

将数组转化为集合

asList 调用Arrays.类的静态方法asList()

1
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arrays));
1
HashSet<Character> list1 = new HashSet<Character>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
1
2
List<String> list = Arrays.asList(new String[]{"aa", "bb"});
System.out.println(list);//[aa, bb]

使用Collections.addAll()

1
2
List<String> list2 = new ArrayList<String>(arrays.length);
Collections.addAll(list2, arrays);

迭代器

迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元
素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。

Iterator

Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。

1
2
3
4
5
6
7
8
9
10
11
Collection arrayList1 = new ArrayList();
arrayList1.add(123);//int
arrayList1.add(new String("Huiex"));//String
arrayList1.add(false);//布尔
arrayList1.add(new Person("胖子君",19));//对象

Iterator iterator = arrayList1.iterator();//创建一个arrayList1的迭代器对象

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

Iterator iterator = arrayList1.iterator();

  • Ilterator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。

  • 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。

iterator.hasNext()

判断是否还有下一 个元素

iterator.next()

指针下移 并将下移以后集合位置上的元素返回

remove

删除集合中的元素

1
2
3
4
5
6
7
8
9
10
11
//一边遍历一边删除集合中的元素,遍历结果不含要删除的元素
Iterator iterator = arrayList2.iterator();
while (iterator.hasNext()){
Object o = iterator.next();
if ("Huiex".equals(o)){
iterator.remove();
}
else {
System.out.println(o);
}
}

和之前remove不同在于 上面是明确知道要删除的元素,而这个是不想在遍历出来的结果出现某个元素,起到过滤作用

List

存储

存储有序的、可重复的数据。 集合中的每个元素都有其对应的顺序索引。可以当做“动态”数组 列表

List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

子类

List的子类 ArrayList LinkedList Vector

ArrayList LinkedList Vector 三者的异同

1
ArrayList    作为ist接口的主要实现类;线程不安全的,效率高;底层使用bject[]存储
1
2
LinkedList   对于频繁的插入、删除操作,使用此类效率比Arpayttst高; 底层使用双向链表度储
LinkedList集合不仅提供了List的功能,还额外提供了的双向队列、栈的功能
1
Vector 		 作为List接口的古老实现类:线程安全的,效率低;底层使用object[]存储

ArrayList

方法

1
2
3
4
5
6
ArrayList list = new ArrayList();
list.add(123);
list.add("Huiex");
list.add(new Person("胖子君",19));
list.add(false);
list.add(123);

添加

void add(int index, Object ele):在index位置插入ele元素

1
2
list.add(2,"abc");//在list中的第二个索引位置添加元素
System.out.println(list);

boolean addALl(int index, Collection eles): M从index位置开始将eLes中的所有元素添加

1
2
3
4
List<Integer> list1 = Arrays.asList(1, 2, 3);
list.addAll(list1);
System.out.println(list);
//[123,abc,Huiex,Person{name='胖子君', age=19}, false, 123,1, 2, 3]

删除

int indexOf(object obj): 返回obj在当前 集合 中末次出现的位置(索引)(查不到返回-1)

1
System.out.println(list.indexOf(123));//0

Object remove(int index):移除指定index位置的元素,并返回此元素

1
2
3
4
Object o = list.remove(0);
System.out.println(o);//123
System.out.println(list);
//[Huiex, abc, Person{name='胖子君', age=19}, false, 123, 1, 2, 3]

Object remove(object obj) 移除指定的元素,并返回bool

1
list.remove("Huiex");

区分List中remove(int index) 和remove(Object obj)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void test2(){
ArrayList list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);

updateList(list);
System.out.println(list);
}

private static void updateList(List list){
list.remove(2);
list.remove(new Integer(2));
}

结果为[1]

list.remove(2);传的参为int 2,所以删掉 3

list.remove(new Integer(2));传的参为对象 2,所以删掉 2

修改

Object set(int index, object ele):设置指定index位置的元素为ele

1
2
list.set(1,"Huiex");
System.out.println(list);//[abc, Huiex, false, 123, 1, 2, 3]

查找

object get(int index):获取指定index位置的元素

1
System.out.println(list.get(0));//123

int LastIndexOf(object obj):返回obj在当前集合中末次出现的位置

1
System.out.println(list.lastIndexOf(123));//5

List sublist(int fromIndex, int toIndex):返回一个新list 从fromIndex到toIndex位置的左闭右开区

1
2
List list2 = list.subList(1, 5);
System.out.println(list2);//[Huiex, false, 123, 1]

Vector

Vector 可实现自动增长的对象数组。

java.util.vector提供了向量类(Vector)以实现类似动态数组的功能

同样可以使用ArrayList中的API

作用

对于预先不知或者不愿预先定义数组大小,并且需要频繁地进行查找,插入,删除工作的情况,可以考虑使用向量类。

构造方法

1
2
3
4
5
6
7
public vector()   第一种构造方法创建一个默认的向量,默认大小为 10:

public vector(int initialcapacity,int capacityIncrement) 指定大小的向量,并且增量用 capacityIncrement指定。增量表示向量每次增加的元素数目

public vector(int initialcapacity) 创建指定大小的向量。

public Vector(Collection c) 创建一个包含集合 c 元素的向量:
  • initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时。系统会扩充向量对象存储容量。

  • 参数capacityincrement给定了每次扩充的扩充值。当capacityincrement为0的时候,则每次扩充一倍,利用这个功能可以优化存储。

方法

添加

1
2
public final synchronized void addElement(Object obj) 
将obj插入向量的尾部
1
2
public final synchronized void setElementAt(Object obj,int index) 
将index处的对象设置成obj,原来的对象将被覆盖。

删除

1
2
public final synchronized void removeElement(Object obj) 
从向量中删除obj,若有多个存在,则从向量头开始试,删除找到的第一个与obj相同的向量成员。
1
2
public final synchronized void removeAllElement(); 
删除向量所有的对象
1
2
public fianl synchronized void removeElementAt(int index)
删除index所指的地方的对象

查找

1
2
public final int indexOf(Object obj) 
从向量头开始搜索obj,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1.
1
2
public final synchronized int indexOf(Object obj,int index) 
从index所表示的下标处开始搜索obj.
1
2
public final synchornized firstElement() 
获取向量对象中的首个obj
1
2
public final synchornized Object lastElement() 
获取向量对象的最后一个obj

其他

1
2
public final int size(); 
此方法用于获取向量元素的个数。它们返回值是向量中实际存在的元素个数,而非向量容量。可以调用方法 capacity()来获取容量值。
1
2
public final synchronized void setSize(int newsize); 
此方法用来定义向量的大小,若向量对象现有成员个数已经超过了newsize的值,则超过部分的多余元素会丢 失。 程序中定义Enumeration类的一个对象Enumeration是java.util中的一个接口类,

Stack

Stack类继承自Vector类

由于Stack和继承于Vector,因此它也包含Vector中的全部API

创建

Stack是类,可以直接创建

1
Stack<Integer> stack = new Stack<>();

方法

1
2
3
4
5
6
7
E push(E item)	压入栈顶

E peek() 返回栈顶对象,不移除
E pop() 返回栈顶对象,并移除

int search(Object o) 返回对象在栈的位置
boolean empty() 判断栈是否为空

Set

定义

存储无序的、不可重复的数据 就是高中讲的集合 集合

​ HashSet、LinkedHashSet、 TreeSet

Set接口:存储==无序的、不可重复的数据==

以HashSet为例说明:

  • 无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值

    哈希表边存放的是哈希值。HashSet 存储元素的顺序并不是按照存入时的顺序(和 List 显然不同) 而是按照哈希值来存的所以取数据也是按照哈希值取得

  • 不可重复性:保证添加的元素按照equals()判断时,不能返回true.即:相同的元素只能添加一 个

HashSet、LinkedHashSet、TreeSet三者的异同:

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

  • LinkedHashSet: 作为HashSet的子类; 遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,

    L inkedHashSet效率高FHashSet.

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

Set的方法 和 list一致

Set添加元素原理

添加元素的过程:以HashSet 为例:

1
2
3
4
5
6
7
8
9
10
11
12
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,

此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断

数组此位置上是否已经有元素:

- ​ 如果此位置上没有其他元素,则元素a添加成功。
- ​ 如果此位置上有其他元素b,或以链表形式存在的多个元素),则比较元素a与元素b的hash值
- 如果hash值不相同,则元素a添加成功。
- 如果hash值相同,进而需要调用元素a所在类的equlas()方法:
- equals()返回true,元素a添加失败
- equals()返回false,则元素q添加成功。

==向Set中添加的数据,其所在的类一定要重写hashCode()和equals()==

方法

添加

1
2
add() //将指定的元素添加到集合中
addAll() //将指定集合的所有元素添加到集合中

删除

1
2
3
boolean remove(Object o);  //从集合中移除指定的元素
boolean removeAll(Collection<?> c); //从存在于另一个指定集合中的集合中删除所有元素
void clear(); //删除所以的元素

长度

1
int size();

判断

1
2
3
4
boolean isEmpty();
boolean contains(Object o); //如果集合包含指定的元素,则返回true
boolean containsAll(Collection<?> c); //如果集合包含指定集合的所有元素,则返回true
boolean retainAll(Collection<?> c);
1
hashCode() -返回哈希码值(集合中元素的地址)

Queue

创建

1
Queue<String,String> queue = new LinkedList<>();

==因为queue是接口,不能new 接口,应该new接口实现类==

img

下面有一大堆实现queue的类,选一个就行,针对队列的,你可以选LinkedBlockingQueue, AbstrctQueue, ArrayDeque

方法

添加

压入元素(添加):add()、offer()
相同:未超出容量,从队尾压入元素,返回压入的那个元素。
区别:在超出容量时,add()方法会对抛出异常,offer()返回false

删除

弹出元素(删除):remove()、poll()
相同:容量大于0的时候,删除并返回队头被删除的那个元素。
区别:在容量为0的时候,remove()会抛出异常,poll()返回false

不删除

获取队头元素(不删除):element()、peek()
相同:容量大于0的时候,都返回队头元素。但是不删除。
区别:容量为0的时候,element()会抛出异常,peek()返回null。

Deque

双端队列 Deque是一个线性collection,支持在两端插入和移除元素

有三种用途 双端队列 普通队列 栈

1
Deque deque = new LinkedList();

双端队列

image-20211206211455336

队列

image-20211206211354111

image-20211206211721485

PriorityQueue堆

优先队列

排序的时间复杂度是 N

创建

默认为小根堆,实现大根堆需要重写一下比较器。

1
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>((Integer v1,Integer v2) -> v2 - v1);

方法

添加

向优先队列中插入元素 add(E e) offer(E e)

删除

poll()

删除元素:删除堆顶元素——队列为空的时候返回null

remove()

删除堆顶元素——队列为空的时候抛出异常NoSuchElementException()

不删除

peek()

获取队列顶部元素——仅仅获取,没有删除

element()

获取堆顶元素——队列为空抛异常NoSuchElementException()

Map

Map接口

双列集合,用来存储一-对(key - volue) 一对的数据

​ HashMap、 L inkedHashMap、 TreeMap、 Hashtable、Properties

Map:双列数据,存储key-value对的数据

HashMap、TreeMap、Hashtable三者的异同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- HashMap:
作为Map的主要实现类;线程不安全的,效率高;存储null的key和value

- LinkedHashMap:保证在遍历map元素时, 可以按照添加的顺序实现遍历。

原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。

对于频繁的遍历操作,此类执行效率高于HashMap

- TreeMap

保证按照添加的key-value对进行排序,实现排序遍历。 此时考虑key的自然排序或定制排序

- Hashtable:

作为古老的实现类;线程安全的,效率低;不能存储nuLL的key和value

map存储原理图

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

HashMap底层原理

以jdk7为例说明

HashMap map = new HashMap():
在实例化以后,底层创建了长度是16的一维数组Entry[] table

map. put(key1, value1):
首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。

  • 如果此位置_上的数据为空,此时的key1-value1 添加成功。—- 情况1

  • 如果此位置上的数据不为空,(意昧着此位置上存在-一个或多个数据(以链表形式存在)),比较key1和已经存在的-一个或多个数据的哈希值:

    • 如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1 添加成功。—- 情况2

    • 如果key1的哈希值和已经存在的某一个数 据(key2-value2)的哈希值相同,继续比较:调用key1 所在类的equals(key2)

      • 如果equals()返回faLse:此时key1-value1添加成功。—-情况3

      • 如果equaLs()返回true:使用value1替换value2。

补充:关于情况2和情况3:此时key1-value1 和原来的数据以链表的方式存储。

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

jdk8

相较于jdk7在底层实现方面的不同:

  1. new HashMap():底层没有创建一 个长度为16的数组
  2. jdk 8底层的数组是: Node[],而非Entry[] .
  3. 首次调用put()方法时,底层创建长度为16的数组
  4. jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。
    当数组的某- -个索引位置上的元素以链表形式存在的数据个数> 8且当前数组的长度> 64时,
    此时此索引位置上的所有数据改为使用红黑树存储。

方法

添加/修改

1
2
3
4
5
6
7
8
put(key,value) 
HashMap map = new HashMap();
//添加
map.put("AA",123);
map.put(456,789);
//修改
map.put("AA",789);
System.out.println(map);{AA=789, 456=789}

删除

1
2
3
4
Object remove(key)	
Object o = map.remove("AA");
System.out.println(o);789
System.out.println(map);{456=789}
1
2
3
4
clear() 	//清空map中的键值对
map.clear();
System.out.println(map.size());0
System.out.println(map);{}

查询

1
2
3
4
5
6
7
Object get(Object key)    //获取指定key对应的value
HashMap map = new HashMap();
map.put("AA",123);
map.put(123,456);
map.put("BB",123);

System.out.println(map.get("AA"));123
1
Object getOrDefault(Object key, Object o); //获取指定key的value,如果没有就默认返回o
1
2
boolean containsKey(Object key) //是否包含指定的key
boolean isExist = map.containsKey("BB");true
1
2
boolean containsValue(Object value)  //是否包含指定的value
System.out.println(map.containsValue(456));true
1
int size()   //返回map中key-value对的个数
1
hoolean isEmpty()  //判断当前map是否为空
1
boolean eqyals(object obj) //判断当前map和参数对象obj是否相等

遍历

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

1
2
3
4
5
6
7
8
9
10
11
12
13
HashMap map = new HashMap();

map.put("AA",123);
map.put(456,123);
map.put("BB","BB");

//遍历所有的key集: keySet()
Set set = map.keySet();将key存入set中
Iterator iterator = set.iterator();再遍历set
while (iterator.hasNext()){
System.out.println(iterator.next());
}

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

1
2
3
4
5
6
//遍历所有value:value()
Collection values = map.values();
Iterator iterator1 = values.iterator();再遍历set
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}

方法一

Set entrySet(): 返回所有key-value对构成的Set集合

1
2
3
4
5
6
7
8
//遍历所有的key-value
//entrySet():
Map.Entry entrySet = map.entrySet();
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()){
Map.Entry entry = (Map.Entry)iterator2.next();//强转一下Map.Entry类型
System.out.println(entry.getKey() + "--->" + entry.getValue());
}

方法二

返回所有key构成的Set集合,再用key查询 value;

1
2
3
4
5
6
7
Set keySet = map.keySet();
Iterator iterator3 = keySet.iterator();
while (iterator.hasNext()){
Object key = iterator.next();
Object value = map.get(key);
System.out.println(key + "--->" + value);
}

根据键、值排序

以Key进行排序

我们可以声明一个TreeMap对象

然后往map中添加元素,通过输出结果,可以发现map里面的元素都是排好序的

1
Map<Integer, Person> map = new TreeMap<Integer, Person>()

想自定义的话 就在构造器的参数里面重新Comparator();

以value进行排序

先声明一个HashMap对象

将Map集合转换成List集合,最后借助Collections工具类进行排序

1
2
3
4
5
6
7
8
9
Map<String, Integer> map = new HashMap<String, Integer>();
List<Map.Entry<String,Integer>> list = new ArrayList<MEntry<String,Integer>>(map.entrySet())

Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1,
Map.Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
}
});

这样就实现了Map中的value按逆序排序,如果需要升序排的话,只需要修改o2.getValue()-o1.getValue()为o1.getValue()-o2.getValue()即可。

String

String:字符串,使用一对“ ”引号起来表示。

String实现了Serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String 可以比较大小

不能不初始化字符串

1
2
String str;
str.sout;

str是对象,你这是啥,空间都没有开辟

不可变性

==String声明为final的,不可被继承== String内部定义了final char[] value用于存储字符串数据

代表不可变的字符序列。简称:不可变性

体现: 1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。

​ 2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

​ 3.当调用String的replace()方法修改字符或字符事时,也需要重新指定内存区域赋值

1
2
3
4
String s1 = "abc";
String s2 = s1.replace("a","d");
sout s1 //abc
sout s2 //dbc

String的实例化

image-20211013185558470

通过字面量定义的方式

通过字面量的方式String s1 = “abc”(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中

字符串常量池中是不会存储相同内容的字符串的

通过new +构造器的方式

通过new +构造器的方式 String s2 = new String(“abc”) 此时的s2保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。

常量与常量的拼接 “abc” +“def” 结果在常量池。且常量池中不会存在相同内容的常量

变量与常量 s1 + “abc”的拼接结果只在堆中

如果拼接的结果调用intern()方法,返回值就在常量池中

相关题

方法将 一个字符串 还有一个字符数组 改变,主函数输出是否会受到影响

image-20211013204834324

因为 str为引用数据类型,传递给形参的是地址

而char []中的char[0]是char为基本数据类型,传递的是真实存储的数据值,能够被改变

String类方法

大小写

1
2
 String toLowerCase():使用默认语言环境,将String中的所有字符转换为小写,不改变原字符串
String toUpperCase():使用默认语言环境,将String中的所有字符转换为大写,不改变原字符串

去除两端

1
String trim():返回字符串的副本,忽略前导空白和尾部空白

比较

1
2
3
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
int compareTo(String anotherString):比较两个字符串的-大小-(字符床中每个字符的大小)(结果为负数表示小,正数大)

拼接

1
String concat(String str):将指定字符串连接到此字符串的结尾。等价于用“+”

截取

1
2
3
4
5
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
String substring(int beginIndex,int endIndex):返回一个新字符串,它是此字符串从beginIndex开始截取到enendIndex(左闭右开,从0开始)
String substringAfterLast() 截取字符函数substring
StringUtils.substringAfterLast(originalFilename, ".");
将originalFilename字符串从“.”符号 最后一次出现的位置向后截取

判断

1
2
3
4
boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
boolean isDigit(char ch) 如果字符为数字,则返回 true;否则返回 false

查找

1
2
3
4
5
6
7
8
boolean isEmpty():判断是否是空字符串:return value.length==0
char charAt(int index):返回某索引处的字符return value[index]
boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true

int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,(从指定的索引开始反向搜索)

替换

1
2
3
4
5
String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。

1
2
3
4
Java删除字符串中的指定字符
替换函数,替换成空白
String test = ("chaojimali");
test = test.replace("chaoji","");//replace产生一个新字符串

切片

1
2
3
4
5
6
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

int[] arr = s.split(" ");
如果s为 "hello world"(两个单词之间有3个空格)
执行 s.split(" ")后 为arr = ["hello","","","woeld"]中间会出现俩个空字符串

翻转字符串

1
2
3
String reverse = new StringBuffer(string).reverse().toString();
System.out.println("字符串反转前:"+string);
System.out.println("字符串反转后:"+reverse);

类型转换

int <==> String

String –> 基本数据类型、包装类

调用包装类的静态方法:parseXxx(str)

1
2
3
String str1 = "123";
// int num = (int)str1;//错误的
int num = Integer.parseInt(str1);

基本数据类型、包装类 –> String

调用String重载的valueOf(xxx) 或者 拼接“ ”

1
2
3
4
String str2 = String.valueOf(num);   //"123
String str3 = num + "";

System.out.println(str1 == str3); //false

char[] <==> String

String –> char[]

调用String的toCharArray()

1
2
String str1 = "abc"; 
char[] charArray = str1.toCharArray();//['a','b','c']

char[] –> String

调用String的构造器

1
2
char[] arr = new char[]{'h','e','l','l','o'};
String str2 = new String(arr);

char <==> String

char –> String

1
String s = String.valueOf('c'); //效率最高的方法

String –> char

1
char c = str.charAt(i);//将字符串指点索引下的字符转换为char

StringBuffer

异同

String、StringBuffer、StringBuilder三者的异同?

  • String:不可变的字符序列;底层使用char[]存储
  • StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储
  • StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储

原理

StringBuffe和StringBuilder 默认初始化会构建一个长度为16的数组,

1
2
StringBuffer sb1 = new StringBuffer();
//char[] value = new char[16];底层创建了一个长度是16的数组。
1
2
StringBuffer sb2 = new StringBuffer("abc");
//char[] value = new char["abc".length() + 16];

如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。

默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组中ofCopy()方法

初始化

使用构造器,手动定义新建的数组长度capacity,否则默认长度为16

1
2
3
StringBuffer sb1 = new StringBuffer(int capacity) 

StringBuffer sb2 = new StringBuilder(int capacity)

常用方法

1
2
StringBuffer append(String xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer insert(int offset, xxx):在指定位置插入xxx

1
2
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer deleteCharAt(int a) 删除指定索引的内容

1
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str

1
2
3
4
int indexOf(String str)  str在字符串中的位置  没有返回-1
String substring(int start,int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串
char charAt(int n) 查询目标索引下的的字符
void setCharAt(int n ,char ch)
1
StringBuffer reverse() :把当前字符序列逆转    

长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int length(): 字符串长度
int capacity():容量

1.StringBuffer的的初始大小为(16+初始字符串长度)
2.一旦length大于capacity时,capacity便在前一次的基础上加1后倍增;
但有如下特殊情况:
/** StringBuffer sb3=new StringBuffer("a");
System.out.println("length="+sb3.length());//length=1
System.out.println("capacity="+sb3.capacity());//capacity=17;

sb3.append("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");//length=19
System.out.println("length="+sb3.length());//length=1+19=20;
System.out.println("capacity="+sb3.capacity());//capacity=40;*/
当length>capacity时,capacity倍增仍达不到length的长度,这种现象称为跨阶,此时,capacity将根据length的实际大小设置长度,此后将按照直接倍增的方式增长(不将length+1)

String之间的转化

String —> StringBuffer

通过构造方法

1
StringBuffer sb = new StringBuffer(String s);

通过append()方法

1
2
3
4
        String s = "abc";        
StringBuffer sb = new StringBuffer();
sb.append(s);
}

StringBuffer —> String

通过构造方法

1
2
StringBuffer sb = new StringBuffer("abc");
String s = new String(sb);

通过toString()方法

1
2
StringBuffer sb = new StringBuffer("abc");
String s = sb.toString();

Arrays

包:import java.util.Arrays

Arrays工具类都是静态的

网址:Java Arrays工具类 (biancheng.net)

比较

1
boolean equals(int[] a,int[] b)	判断两个数组是否相等(元素逐个比较)

输出

1
2
String toString(int[] a)	输出数组信息
deepToString(Object[][] arrays) 返回多维数组的字符串形式 [[1, 2], [3, 4]]

转换

1
2
3
4
String toString(type[] a) 
将一个数组转换成一个字符串。该方法按顺序把多个数组元素连缀在一起,多个数组元素使用英文逗号`,`和空格隔开。
List asList() 数组转化为List集合
这个数组一定要是引用类型才能将其转换为List集合,当传入基本数据类型数组时则会将这个数组对象当成一个引用类型对象存进List集合。

添加

1
void fill(int[] a,int val)	将指定值填充到数组之中  一般用于初始化数组

排序

1
void sort(int[] a)	对数组进行排序。(快速排序)  时间复杂度为 nlogn

查找

1
int binarySearch(int[] a,int key)	对排序后的数组进行二分法检索指定的值,如果查找到,返回索引,如果没有,返回负数

复制

1
2
type[] copyOf(type[] original, int length)  
会把 original 数组复制成一个新数组,其中 length 是新数组的长度如果 length 小于 original 数组的长度,则新数组就是原数组的前面 length 个元素,如果 length 大于 original 数组的长度,则新数组的前面元索就是原数组的所有元素,后面补充 0(数值类型)、false(布尔类型)或者 null(引用类型)

切片

1
2
3
4
5
copyOfRange(被切片的数组, begin_index, end_index)//左闭右开
int[] test_int = new int[] { 1, 2, 3, 4, 5};
test_int = Arrays.copyOfRange(test_int, 1, 4);
System.out.println(Arrays.toString(test_int));//[2,3,4]
如果 begin_index, end_index 相同 就返回一个空数组

Math类

java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回值类型一般为double型。

1
2
3
4
5
6
7
8
9
10
11
12
abs 绝对值--------------------<<
acos,asin,atan,cos,sin,tan 三角函数
sqrt 平方根------------------------------------<<
pow(double a,doble b) a的b次幂
log 自然对数
exp e为底指数
max(double a,double b)
min(double a,double b)
random() 返回0.01.0的随机数------------------------------<<
long round(double a) double型数据a转换为long型(四舍五入)
toDegrees(double angrad) 弧度—>角度
toRadians(double angdeg) 角度—>弧度

基本数据类型

int

int是4个字节,32位

2进制 10位数 2147483648 - 2147483647

long

2进制 19位数 9223372036854775807L(long型要加 L )- 9223372036854775808L

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Java基本类型包装类:

基本数据类型 基本类型包装类

byte Byte

short Short

int Integer

long Long

float Float

double Double

char Character

boolean Boolean

Integer

Java中的Integer - 一只水饺 - 博客园 (cnblogs.com)

常量

最大的Int为: Integer.MAX_VALUE

最小的Int为: Integer.MIN_VALUE

构造方法

Integer(int number)该方法以一个int型变量作为参数来获取Integer对象。

1
Intrger number = new Integer(7);

Integer和int之间的转换

int到Integer:

int a=3;

Integer A=new Integer(a);

或:

Integer A=Integer.valueOf(a);

Integer到int:

Integer A=new Integer(5);

int a=A.intValue();

常用方法

image-20220326203630294

进制转换

Integer类的toString()方法,可将Integer对象转换为十进制字符串表示。toBinaryString()、toHexString()和toOctalString()方法分别将值转换成二进制、十六进制和八进制字符串

1
2
3
4
5
6
7
8
9
10
11
12
public class Charac { // 创建类Charac
public static void main(String args[]) { // 主方法
String str = Integer.toString(456); // 获取数字的十进制表示
String str2 = Integer.toBinaryString(456); // 获取数字的二进制表示
String str3 = Integer.toHexString(456); // 获取数字的十六进制表示
String str4 = Integer.toOctalString(456); // 获取数字的八进制表示
System.out.println("'456'的十进制表示为:" + str);
System.out.println("'456'的二进制表示为:" + str2);
System.out.println("'456'的十六进制表示为:" + str3);
System.out.println("'456'的八进制表示为:" + str4);
}
}

char

char –> int

1
2
char c = '2';
int num = c - '0';

int –> char

1
2
int num =1;
char c = (char)(num + '0');

BigInteger

Java.math.BigInteger.gcd()方法实例

java.math.BigInteger.gcd(BigInteger val) 返回一个BigInteger,其值的最大公约数:abs(this) 和 abs(val)。它返回 0 如果 this==0 && val==0.

Java比较器

Java实现对象排序的方式有两种

  • 自然排序:java.lang.Comparable
  • 定制排序:java.util.Comparator

作用

Java中的对象,正常情况下,只能进行比较:==!= 。不能使用 ><

如果对多个对象进行排序,就可以使用使用两个接口中的任何一个:ComparableComparator

Comparable自然排序

像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。

代码默认调用(自然)

例如:

String[] arr = new String[]{“AA”,”CC”,”KK”,”MM”,”GG”,”JJ”,”DD”};

String类就继承了Comparable类,重写了里面的compareTo(obj)方法,通过比较字符的大小,根据重写compareTo(obj)进行比较

1
2
3
4
重写compareTo(obj)的规则:       
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零

自定义类实现自然排序

如果像比较自定义的对象,就需要在该对象类中重写compare(Object o1,Object o2)方法

1
2
3
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,
或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,
那么可以考虑使用 Comparator 的对象来排序

使用Comparable实现定制排序

自己手动定义排序,需要在类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CompareTest {

/**
* 4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。
* 在compareTo(obj)方法中指明如何排序
*/
@Test
public void test2(){
Goods[] arr = new Goods[5];
arr[0] = new Goods("lenovoMouse",34);
arr[1] = new Goods("dellMouse",43);
arr[2] = new Goods("xiaomiMouse",12);
arr[3] = new Goods("huaweiMouse",65);
arr[4] = new Goods("microsoftMouse",43);

Arrays.sort(arr);

System.out.println(Arrays.toString(arr));
}

s

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
/**
* 商品类
*/
@Lombok
public class Goods implements Comparable{

private String name;
private double price;

//指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从高到低排序
@Override
public int compareTo(Object o) { -------<<重写了
// System.out.println("**************");
if(o instanceof Goods){
Goods goods = (Goods)o;
//方式一:
if(this.price > goods.price){
return 1;
}else if(this.price < goods.price){
return -1;
}else{
// return 0;
return -this.name.compareTo(goods.name);
}
//方式二:
// return Double.compare(this.price,goods.price);
}
// return 0;
throw new RuntimeException("传入的数据类型不一致!");
}
}

使用Comparator实现定制排序

有些方法里面含义Comparator参数,就可以之间在参数里面写,(匿名类)规定排序方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public void test3(){
String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};
Arrays.sort(arr,new Comparator(){------------------<<<

//按照字符串从大到小的顺序排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof String && o2 instanceof String){
String s1 = (String) o1;
String s2 = (String) o2;
return -s1.compareTo(s2);
}
// return 0;
throw new RuntimeException("输入的数据类型不一致");
}
});
System.out.println(Arrays.toString(arr));
}

compareTo()

1
public int compareTo( NumberSubClass referenceName )

compareTo() 方法用于将 Number 对象与方法的参数进行比较。可用于比较 Byte, Long, Integer等。该方法用于两个相同数据类型的比较,两个不同类型的数据不能用此方法来比较。

返回值

  • 如果指定的数与参数相等返回0。
  • 如果指定的数小于参数返回 -1。
  • 如果指定的数大于参数返回 1。

比较方法

(1) 字符串与对象进行比较

(2) 按字典顺序比较两个字符串

先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值,如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至得到最终结果或者其中一个参数结束。