halisi7

一个专注技术的组织

0%

Java-集合2

Collection子接口之一:List接口

image-20220201102650388

List接口方法

image-20220201103003861

1
2
3
4
5
6
7
8
9
10
总结:常用方法
增:add(Object obj)
删:remove(int index) / remove(Object obj)
改:set(int index, Object ele)
查:get(int index)
插:add(int index, Object ele)
长度:size()
遍历:① Iterator迭代器方式
② 增强for循环
③ 普通的循环
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
@Test
public void test1(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");
list.add(new Person("Tom",12));
list.add(456);

System.out.println(list);

//void add(int index, Object ele):在index位置插入ele元素
list.add(1,"BB");
System.out.println(list);

//boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
List list1 = Arrays.asList(1, 2, 3);
list.addAll(list1);
// list.add(list1);
System.out.println(list.size());//9

//Object get(int index):获取指定index位置的元素
System.out.println(list.get(0));

}
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
@Test
public void test2(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");
list.add(new Person("Tom",12));
list.add(456);
//int indexOf(Object obj):返回obj在集合中首次出现的位置。如果不存在,返回-1.
int index = list.indexOf(4567);
System.out.println(index);

//int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置。如果不存在,返回-1.
System.out.println(list.lastIndexOf(456));

//Object remove(int index):移除指定index位置的元素,并返回此元素
Object obj = list.remove(0);
System.out.println(obj);
System.out.println(list);

//Object set(int index, Object ele):设置指定index位置的元素为ele
list.set(1,"CC");
System.out.println(list);

//List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的左闭右开区间的子集合
List subList = list.subList(2, 4);
System.out.println(subList);
System.out.println(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
@Test
public void test3(){
ArrayList list = new ArrayList();
list.add(123);
list.add(456);
list.add("AA");

//方式一:Iterator迭代器方式
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}

System.out.println("***************");

//方式二:增强for循环
for(Object obj : list){
System.out.println(obj);
}

System.out.println("***************");

//方式三:普通for循环
for(int i = 0;i < list.size();i++){
System.out.println(list.get(i));
}



}

面试题:

image-20220201103745313

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ListExer {
/*
区分List中remove(int index)和remove(Object obj)
*/
@Test
public void testListRemove() {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
updateList(list);
System.out.println(list);//1,3
}

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

}

Collection子接口之二:Set接口

image-20220201115425515

image-20220201115445463

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1. Set接口的框架:
*
* |----Collection接口:单列集合,用来存储一个一个的对象
* |----Set接口:存储无序的、不可重复的数据 -->高中讲的“集合”
* |----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null
* |----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历
* 对于频繁的遍历操作,LinkedHashSet效率高于HashSet.
* |----TreeSet:可以按照添加对象的指定属性,进行排序。
*
*
* 1. Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。
*
* 2. 要求:向Set(主要指:HashSet、LinkedHashSet)中添加的数据,其所在的类一定要重写hashCode()和equals()
* 要求:重写的hashCode()和equals()尽可能保持一致性:相等的对象必须具有相等的散列码
* 重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。

HashSet中添加元素的过程:

image-20220201115735294

image-20220201115747534

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
一、Set:存储无序的、不可重复的数据
以HashSet为例说明:
1. 无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定的。

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

二、添加元素的过程:以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添加成功。--->情况2

对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。
jdk 7 :元素a放到数组中,指向原来的元素。
jdk 8 :原来的元素在数组中,指向元素a
总结:七上八下

HashSet底层:数组+链表的结构。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test1(){
Set set = new HashSet();
set.add(456);
set.add(123);
set.add(123);
set.add("AA");
set.add("CC");
set.add(new User("Tom",12));
set.add(new User("Tom",12));
set.add(129);

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

关于hashCode()与equals()的重写

image-20220201121027800

image-20220201121047513

image-20220201121105402

LinkedHashSet

image-20220201121256572

1
2
3
4
//LinkedHashSet的使用
//LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个
//数据和后一个数据。
//优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void test2(){
Set set = new LinkedHashSet();
set.add(456);
set.add(123);
set.add(123);
set.add("AA");
set.add("CC");
set.add(new User("Tom",12));
set.add(new User("Tom",12));
set.add(129);

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

Set实现类之三:TreeSet(了解)

image-20220201141515148

image-20220201141533303

image-20220201142001197

image-20220201141834044

image-20220201142041443

1
2
3
4
5
6
7
8
/*
1.向TreeSet中添加的数据,要求是相同类的对象。
2.两种排序方式:自然排序(实现Comparable接口) 和 定制排序(Comparator)


3.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0.不再是equals().
4.定制排序中,比较两个对象是否相同的标准为:compare()返回0.不再是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
@Test
public void test1(){
TreeSet set = new TreeSet();

//失败:不能添加不同类的对象
// set.add(123);
// set.add(456);
// set.add("AA");
// set.add(new User("Tom",12));

//举例一:
// set.add(34);
// set.add(-34);
// set.add(43);
// set.add(11);
// set.add(8);

//举例二:
set.add(new User("Tom",12));
set.add(new User("Jerry",32));
set.add(new User("Jim",2));
set.add(new User("Mike",65));
set.add(new User("Jack",33));
set.add(new User("Jack",56));


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

}
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
@Test
public void test2(){
Comparator com = new Comparator() {
//按照年龄从小到大排列
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else{
throw new RuntimeException("输入的数据类型不匹配");
}
}
};

TreeSet set = new TreeSet(com);
set.add(new User("Tom",12));
set.add(new User("Jerry",32));
set.add(new User("Jim",2));
set.add(new User("Mike",65));
set.add(new User("Mary",33));
set.add(new User("Jack",33));
set.add(new User("Jack",56));


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

练习

练习:在List内去除重复数字值,要求尽量简单

image-20220201145011781

练习二

image-20220201150412574

练习三

image-20220201150841461

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
57
58
59
60
61
62
63
64
65
66
67
68
/**
* 定义一个Employee类。
该类包含:private成员变量name,age,birthday,其中 birthday 为 MyDate 类的对象;
并为每一个属性定义 getter, setter 方法;
并重写 toString 方法输出 name, age, birthday

* @author shkstart
* @create 2019 上午 10:22
*/
public class Employee implements Comparable{
private String name;
private int age;
private MyDate birthday;

public Employee(String name, int age, MyDate birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}

public Employee() {

}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public MyDate getBirthday() {
return birthday;
}

public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}

@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}

//按 name 排序
@Override
public int compareTo(Object o) {
if(o instanceof Employee){
Employee e = (Employee)o;
return this.name.compareTo(e.name);
}
// return 0;
throw new RuntimeException("传入的数据类型不一致!");
}
}
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/**
* MyDate类包含:
private成员变量year,month,day;并为每一个属性定义 getter, setter 方法;

* @author shkstart
* @create 2019 上午 10:21
*/
public class MyDate implements Comparable{
private int year;
private int month;
private int day;

public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}

public MyDate() {

}

public int getYear() {
return year;
}

public void setYear(int year) {
this.year = year;
}

public int getMonth() {
return month;
}

public void setMonth(int month) {
this.month = month;
}

public int getDay() {
return day;
}

public void setDay(int day) {
this.day = day;
}

@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}


@Override
public int compareTo(Object o) {
if(o instanceof MyDate){
MyDate m = (MyDate)o;

//比较年
int minusYear = this.getYear() - m.getYear();
if(minusYear != 0){
return minusYear;
}
//比较月
int minusMonth = this.getMonth() - m.getMonth();
if(minusMonth != 0){
return minusMonth;
}
//比较日
return this.getDay() - m.getDay();
}

throw new RuntimeException("传入的数据类型不一致!");

}
}
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
* 创建该类的 5 个对象,并把这些对象放入 TreeSet 集合中(下一章:TreeSet 需使用泛型来定义)
分别按以下两种方式对集合中的元素进行排序,并遍历输出:

1). 使Employee 实现 Comparable 接口,并按 name 排序
2). 创建 TreeSet 时传入 Comparator对象,按生日日期的先后排序。

*
* @author shkstart
* @create 2019 上午 10:23
*/
public class EmployeeTest {

//问题二:按生日日期的先后排序。
@Test
public void test2(){


TreeSet set = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Employee && o2 instanceof Employee){
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;

MyDate b1 = e1.getBirthday();
MyDate b2 = e2.getBirthday();
//方式一:
// //比较年
// int minusYear = b1.getYear() - b2.getYear();
// if(minusYear != 0){
// return minusYear;
// }
// //比较月
// int minusMonth = b1.getMonth() - b2.getMonth();
// if(minusMonth != 0){
// return minusMonth;
// }
// //比较日
// return b1.getDay() - b2.getDay();

//方式二:
return b1.compareTo(b2);

}
// return 0;
throw new RuntimeException("传入的数据类型不一致!");
}
});

Employee e1 = new Employee("liudehua",55,new MyDate(1965,5,4));
Employee e2 = new Employee("zhangxueyou",43,new MyDate(1987,5,4));
Employee e3 = new Employee("guofucheng",44,new MyDate(1987,5,9));
Employee e4 = new Employee("liming",51,new MyDate(1954,8,12));
Employee e5 = new Employee("liangzhaowei",21,new MyDate(1978,12,4));

set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
set.add(e5);

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


//问题一:使用自然排序
@Test
public void test1(){
TreeSet set = new TreeSet();

Employee e1 = new Employee("liudehua",55,new MyDate(1965,5,4));
Employee e2 = new Employee("zhangxueyou",43,new MyDate(1987,5,4));
Employee e3 = new Employee("guofucheng",44,new MyDate(1987,5,9));
Employee e4 = new Employee("liming",51,new MyDate(1954,8,12));
Employee e5 = new Employee("liangzhaowei",21,new MyDate(1978,12,4));

set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
set.add(e5);

Iterator iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
打赏一下作者~ ฅ( ̳• ◡ • ̳)ฅ