前言

b站java课程学习笔记整理。

b站视频: 黑马程序员全套Java教程_Java基础入门视频教程,零基础小白自学Java必备教程

220. 集合体系结构

集合类的体系结构

221. collection集合的概述和使用

collect是单列集合的顶层接口,他表示一组对象,这些对象也成为Collection元素。

JDK不提供此接口的任何直接实现,它提供更具体的子接口(如SetList)实现。

创建Collection集合的对象

  • 多态的形式
  • 具体的实现类ArrayList
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package Collection演示;

import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();

// 添加元素(和ArrayList方法一样)
c.add("hello");
c.add("world");
// 重写了toString方法
System.out.println(c);
}
}

222.Collection集合的常见用法

方法名 说明
boolean add(E e) 添加元素
boolean remove(Object o) 从集合中移除指定的元素
void clear() 清空集合中的元素
boolean contains(Object o) 判断集合中是否存在指定元素
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中元素的个数
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
package Collection演示;

import java.util.ArrayList;
import java.util.Collection;

public class CollectionDemo2 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
System.out.println(c.add("Hello")); //输出的是是否添加成功,调用add方法永远返回的都是true。
c.add("World");
c.add("World");

System.out.println(c);

c.remove("World");
c.remove("asdasd"); //返回的是false,没有这个字符串。
System.out.println(c); //一次只能去除一个。

boolean flag = c.contains("Hello");
System.out.println(flag);

c.clear();
System.out.println(c);

System.out.println(c.isEmpty());


}
}

223.Collection集合的遍历

Iterator: 迭代器,集合的专用遍历方式。他是依赖于集合的存在。("一个一个找元素"器)

迭代器的方法:

  • E next(): 返回迭代中的下一个元素。
  • boolean hasNext(): 如果迭代具有更多元素,则返回true
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
package Collection演示;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionDemo3 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
System.out.println(c.add("Hello")); //输出的是是否添加成功,调用add方法永远返回的都是true。
c.add("World");
c.add("java");

Iterator<String> it = c.iterator();

/* System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());*/

// 异常:System.out.println(it.next());
while(it.hasNext()){
String s =it.next();
System.out.println(s);
}


}
}

224.集合使用步骤图解

说白了就是指针。

Collection图解

225.collection集合存储学生对象并遍历

和之前那个Arraylist项目差不多,不同的是collection集合可以使用迭代器遍历。

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
package Collection集合存储学生对象;

import 存储学生对象并遍历.Student;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class test {
public static void main(String[] args) {
Student s1 = new Student("林青霞", "30");
Student s2 = new Student("张曼玉", "14");
Student s3 = new Student("王祖贤", "18");

Collection<Student> c = new ArrayList<>();
c.add(s1);
c.add(s2);
c.add(s3);

Iterator<Student> it = c.iterator();

while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName() + s.getAge());
}


}
}

226.list集合

list继承自collection集合,collection集合中的功能都能用。

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
package list集合;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class listDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();

list.add("hello");
list.add("world");
list.add("world");

System.out.println(list);

Iterator<String> it = list.iterator();

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

}
}

227.list集合特有功能

这些功能,他的父类collection没有,但是子类ArrayList有。

这些方法是:

方法 作用
void add(int index, E element) 在指定位置插入元素
E remove(int index) 删除指定索引处的元素
E set(int index, E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
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
package list集合;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class listDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();

list.add("hello");
list.add("world");
list.add("world");

list.add(2, "nihao");
System.out.println(list);

list.remove(3);
System.out.println(list);

System.out.println(list.set(1, "JaveA"));
System.out.println(list);

System.out.println(list.get(1));

// 另一种方法遍历
int j = list.size();
for (int i = 0; i < j; i++) {
System.out.println(list.get(i));
}

}
}

228.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
33
package list存储学生对象;

import 存储学生对象并遍历.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ListDemo {
public static void main(String[] args) {
Student s1 = new Student("林青霞", "30");
Student s2 = new Student("风清扬", "29");
Student s3 = new Student("左冷禅", "28");

List<Student> l = new ArrayList<Student>();
l.add(s1);
l.add(s2);
l.add(s3);

// 遍历可以用collection的迭代器,也可以用for循环和.get结合
Iterator<Student> iterator = l.iterator();
while (iterator.hasNext()) {
Student s = iterator.next();
System.out.println(s.getName() + "," + s.getAge());
}
System.out.println("--------------");

for (int i = 0; i < l.size(); i++) {
System.out.println(l.get(i).getName() + "," + l.get(i).getAge());
}
}
}

229.并发修改异常

说人话总结: 使用迭代器进行迭代的时候不能增加和减少元素的个数。

比如,老板叫迭代器去搬十块砖。迭代器接到命令就去干活了。等到搬到第八块砖的时候迭代器接到老板电话,说改要求需要他去搬十一块砖了。

这和迭代器一开始签的搬十块砖的合同不一样,违约了。迭代器一生气不干了!

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
package list集合;

import 存储学生对象并遍历.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class listDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();

list.add("hello");
list.add("world");
list.add("java");

// 产生并发修改异常
/*Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if(s.equals("world")){
list.add("javaee");

}

}*/
// 用for循环解决问题。
for(int i=0; i<list.size();i++){
String s =list.get(i);
if(s.equals("world")){
list.add("javaee");
}
}
System.out.println(list);

}
}

230.列表迭代器

ListIterator:列表迭代器

  • 通过List集合的listIterator()方法得到,所以说它是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
33
34
35
36
37
38
package list集合;

import 存储学生对象并遍历.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class listDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();

list.add("hello");
list.add("world");
list.add("java");

// 产生并发修改异常
/*Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if(s.equals("world")){
list.add("javaee");
// 通过添加break也可以解决错误
}

}*/
ListIterator<String> lit = list.listIterator();
while(lit.hasNext()){
String s = lit.next();
if(s.equals("world")) {
lit.add("javaee");
}
}
System.out.println(list);
}
}

ListIteratorIterator功能大致相同,都有hasnextnext

但是ListIteratoradd功能不会有并发修改异常。

231.增强for循环

增强for:简化ListCollection集合的遍历

  • 实现Iterable接口的类允许其对象成为增强型for语句的目标
  • 它是JDK5之后出现的。其内部原理是一个Iterator迭代器。
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
package 增强for;

import java.util.ArrayList;
import java.util.List;

public class ForDemo {
public static void main(String[] args) {
int[] arr = {1, 3, 6, 7, 9};
// 对于arr数组里面的每一个int类型的个体i
for (int i : arr) {
System.out.println(i);
}
// 对于arr2数组里面的每一个String类型的个体s
String[] arr2 = {"hello", "world", "java"};
for(String s : arr2){
System.out.println(s);
}

List<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");

/* for(String s: list){
System.out.println(s);
}*/


for(String s: list){
if(s.equals("world")){
list.add("javaee");

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

很奇怪,老师说for增强循环内核是Iterator迭代器,可是我并没有抛出并发错误……

后来才发现原来我的list中是没有world的,那if语句就不执行,就不报错了。

232.list集合存储学生对象用三种方式遍历

三种方式分别为:Iteratorfor增强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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package list学生对象三种遍历;

import 存储学生对象并遍历.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class listDemo {
public static void main(String[] args) {
Student s1 = new Student("林青霞", "21");
Student s2 = new Student("张曼玉", "19");

List<Student> l = new ArrayList<Student>();

l.add(s1);
l.add(s2);

// 迭代器
Iterator<Student> it = l.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName() + "," + s.getAge());
}

// 普通for
for (int i = 0; i < l.size(); i++) {
Student s = l.get(i);
System.out.println(s.getName() + "," + s.getAge());
}

// 增强for
for (Student s : l){
System.out.println(s.getName() + "," + s.getAge());
}
}

}

一般来说就用for就够了。iterator不咋常用。

233.数据结构之栈和队列

栈:

一端开口,先进后出。

队列:

  1. 数据从后端进入队列模型的过程称为:入队列
  2. 数据从前端离开队列模型的过程称为:出队列

队列两端开口,先进先出。

234.数据结构之数组和链表

数组:查询快,增删慢的模型。

  • 查询数据通过索引定位,查询任意数据耗时相同,查询效率高。
  • 删除数据时,要将原始数据删除,同时后面每个数据前移,删除效率低。
  • 添加数据时,添加位置后的每个数据后移,再添加元素,添加效率极低。

链表:节点的存储位置(地址)

链表的一个节点包含了这个节点的地址、数据、下一个节点的地址。

  • 链表是一种增删快的模型(对比数组)
  • 链表是一种查询慢的模型(对比数组)。因为查询数据D是否存在必须从头节点开始查。

235.list集合的子类特点

ArrayListLinkedList,底层数据结构一个是数组一个是列表。 用法和List一样的。(因为是继承)

练习:使用ArrayListLinkedList使用三种方法存储字符串并遍历。

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
package 数组与链表;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

public class test {
public static void main(String[] args) {
// 创建Arraylist
ArrayList<String> al = new ArrayList<>();
al.add("林青霞");
al.add("张曼玉");
al.add("王祖贤");
System.out.println(al);


// 三种方法遍历
// 迭代器

Iterator<String> it = al.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}

//普通for循环

for(int i =0; i < al.size(); i++){
String s = al.get(i);
System.out.println(s);
}

// 增强for循环
for(String s : al){
System.out.println(s);
}

// 创建链表
LinkedList<String> ll = new LinkedList<>();
ll.add("学雷锋");
ll.add("做好事");
ll.add("不留名");

//迭代器
Iterator<String> itr = ll.iterator();
while(itr.hasNext()){
String s = itr.next();
System.out.println(s);
}

//普通for
for(int i =0; i < ll.size(); i++){
String s = ll.get(i);
System.out.println(s);
}

// 增强for循环
for(String s : ll){
System.out.println(s);
}



}
}

236.ArrayList存储学生对象三种遍历

太简单了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package 数组与链表;

import 存储学生对象并遍历.Student;

public class Rewrite extends Student {

public Rewrite() {
}

public Rewrite(String name, String age) {
super(name, age);
}

@Override
public String toString() {
return "姓名是" + getName() + "年龄是"+ getAge();
}
}

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
package 数组与链表;

import 存储学生对象并遍历.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

public class test {
public static void main(String[] args) {
Rewrite s1 = new Rewrite("林青霞","20");
Rewrite s2 = new Rewrite("张曼玉","19");
Rewrite s3 = new Rewrite("郭子维","17");

// 创建Arraylist

ArrayList<Rewrite> al = new ArrayList<>();
al.add(s1);
al.add(s2);
al.add(s3);
System.out.println(al);
System.out.println("----------------------");


// 三种方法遍历
// 迭代器

Iterator<Rewrite> it = al.iterator();
while(it.hasNext()){
Rewrite s = it.next();
System.out.println(s);
}
System.out.println("----------------------");
//普通for循环

for(int i =0; i < al.size(); i++){
Rewrite s = al.get(i);
System.out.println(s);
}
System.out.println("----------------------");
// 增强for循环
for(Student s : al){
System.out.println(s);
}



}
}

为了输出方便,重写了toString方法。

237.LinkedList的特有方法

方法名 说明
public void addFirst(E e) 在该列表的开头插入指定的元素
public void addLast(E e) 在该列表的结尾插入指定的元素
public E getFirst() 返回此列表中的第一个元素
public E getFirst() 返回此列表中的最后一个元素
public E removeFirst() 从此列表中删除并返回第一个元素
public E removeLast() 从此列表中删除并返回最后一个元素
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
package 链表集合特有方法;

import java.util.LinkedList;

public class LinkedListDemo {
public static void main(String[] args) {
// 创建链表

LinkedList<String> ll = new LinkedList<>();

ll.add("林青霞");
ll.add("张曼玉");
ll.add("王祖贤");

// 方法1
ll.addFirst("开头");
System.out.println("方法1"+ll);
// 方法2
ll.addLast("结尾");
System.out.println("方法2"+ll);
// 方法3
System.out.println("方法3"+ll.getFirst());
// 方法4
System.out.println("方法4"+ll.getLast());
// 方法5
System.out.println("方法5"+ll.removeFirst());
System.out.println(ll);
// 方法6
System.out.println("方法6"+ll.removeLast());
System.out.println(ll);
}
}

238.Set集合概述和特点

set集合特点不包含重复的元素,没有带索引的方法,不可以使用for循环遍历。

HashSet对集合的迭代顺序不做任何的保证。

使用SetSet的子类,拓展名要装箱!而String默认已经装箱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.HashSet;
import java.util.Set;

public class SetDemo {
public static void main(String[] args) {
Set<String> s = new HashSet<>();

s.add("林青霞");
s.add("风清扬");
s.add("李冰冰");
s.add("李冰冰");

//两种方式遍历,迭代器或者增强for
for(String i: s){
System.out.println(i); // 不保证输出的顺序,且不能包含重复元素
}

}
}

239.哈希值

哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。

Object类中有一个方法可以获得对象的哈希值。

  • public int hashCode(): 返回对象的哈希码值
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
package 获取哈希值;

import 存储学生对象并遍历.Student;

public class HashDemo {
public static void main(String[] args) {
Student s1 = new Student("林青霞", "12");

// 同一个对象多次调用哈希值,返回的数值相同。
System.out.println(s1.hashCode()); //2129789493
System.out.println(s1.hashCode()); //2129789493

Student s2 = new Student("林青霞", "12");
// 默认情况下不同对象的哈希值是不相同的。如果在Student类中重写hashcode方法,可以实现不同对象的哈希值相同。
System.out.println(s2.hashCode()); //668386784

System.out.println("hello".hashCode()); //99162322
System.out.println("world".hashCode()); //113318802
System.out.println("world".hashCode()); //113318802

System.out.println("重地".hashCode()); // 1179395
System.out.println("通话".hashCode()); // 1179395
// 为什么重地和通话哈希码相同?因为哈希值是有范围的,汉字是无限的。没办法超出编制了,只能发重复哈希码
System.out.println("我的".hashCode());
}


}

为什么“重地”和“通话”哈希码相同?因为哈希值是有范围的,汉字是无限的。没办法超出编制了,只能发重复哈希码。

相同的对象哈希码相同。

240.哈希set集合的概述和特点

  1. 底层数据结构是哈希表。
  2. 对集合迭代顺序不做保证
  3. 没有带索引的方法,不能用普通for循环
  4. 不包括重复元素

补充:个人认为HashSetSet相比优势在于可以自定义什么是“重复数据”。 而且Set也得用HashSet的多态形式实现。属于是一个特例?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package Hashset;

import java.util.HashSet;

public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
hs.add("林青霞");
hs.add("风清扬");
hs.add("王冰冰");
hs.add("王冰冰");
System.out.println(hs);

for(String s : hs){
System.out.println(s);
}

}
}

241.HashSet集合保证元素唯一性的源码分析

HashSet集合保证元素的一致性
没看懂 后面再说吧

242.常见数据结构之哈希表

哈希表默认长度为16。

拉链法解决哈希冲突:

  1. 先哈希值对16取余,算出地址(即需要存储在哪一个格子中)
  2. 再判断该位置是否已经有元素了。
    • 该位置没有元素,那这个元素就是第一个元素
    • 该位置有元素了,比较哈希值。如果哈希值不相同,那以链表的形式添加这个元素。
    • 哈希值也相同,调用qual()方法比较元素内容。元素内容不相同,添加这个元素
    • 元素内容相同,不添加

哈希表

解决了上节的疑惑!

243.HashSet集合存储学生对象并遍历

和之前的项目相同。但是如果学生对象的成员变量相同,那就认为是同一个对象。

思路:

  1. 定义学生类。
  2. 创建HashSet集合对象
  3. 创建学生对象
  4. 把学生添加到集合
  5. 遍历集合(增强for)
  6. 在学生类中重写两个方法hashCode()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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package 存储学生对象并遍历;

public class Student {
private String name;
private String age;

public String getName() {
return name;
}

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

public String getAge() {
return age;
}

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

public Student(){
};

public Student(String name, String age){
this.name = name;
this.age = age;
};


public void show(){
System.out.println("名字是"+name+",年龄是"+age);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Student student = (Student) o;

if (name != null ? !name.equals(student.name) : student.name != null) return false;
return age != null ? age.equals(student.age) : student.age == null;
}

@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
return result;
}
}

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
package Hashset;

import 存储学生对象并遍历.Student;

import java.util.HashSet;

public class StudentDemo {
public static void main(String[] args) {
Student s1 = new Student("林青霞", "张曼玉");
Student s2 = new Student("黄祯", "23");
Student s3 = new Student("我爱罗", "99");

Student s4 = new Student("黄祯", "23");

HashSet<Student> hs = new HashSet<>();

hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
for (Student s : hs) {
System.out.println(s.getName() + "," + s.getAge());
}

}
}

244.LinkedHashSet集合概述和特点

  • 哈希表和链表实现的Set接口,具有可预测的迭代次序。
  • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.LinkedHashSet;
public class LinkedHashSetDemo {
public static void main(String[] args) {

LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("hello");
lhs.add("world");
lhs.add("java");

for(String s:lhs){
System.out.println(s);
}
//输出:hello
// world
// java

lhs.add("java");
for(String s:lhs){
System.out.println(s);
}
}
}

245.TreeSet集合概述和特点

  1. 元素有序,不是存储和取出的排序,而是根据构造方法排序。
    • TreeSet(): 根据其元素的自然排序进行排序
    • TreeSet(Comparator comparator):根据指定的比较器进行排序
  2. 没有带索引的方法,所以不能使用普通for循环遍历
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package TreeSet;

import java.util.TreeSet;

public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<Integer>();

ts.add(10);
ts.add(20);
ts.add(50);
ts.add(40);
ts.add(30);
ts.add(30);

System.out.println(ts);
for (Integer i : ts){
System.out.println(i);
}
}
}

246.Comparable的使用

首先,要想对一个TreeSet的内部元素排序,默认的包装类是可以的。但是如果这个包装类是自己定义的类(比如Student),就必须让这个自定义类实现Comparable 接口。

实现接口后,通过重写CompareTo(T o)方法实现比较。注意实现接口的时候要注明接口的泛型<NewStudent>

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
package TreeSet;

import 存储学生对象并遍历.Student;

public class NewStudent extends Student implements Comparable<NewStudent>{
public NewStudent() {
}

public NewStudent(String name, String age) {
super(name, age);
}

// public String name = getName();


@Override
public int compareTo(NewStudent s) {
int thisAge = Integer.parseInt(this.getAge());
int Age = Integer.parseInt(s.getAge()); //比较的一个是s的,一个是this的。
int num1 = thisAge-Age;
int num2 = num1 == 0? this.getName().compareTo(s.getName()):num1;
return num2;
}

@Override
public String toString() {
return getName()+","+getAge();
}
}

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
package TreeSet;

import java.util.TreeSet;

public class ComparableDemo {
public static void main(String[] args) {
NewStudent s1 = new NewStudent("Qingxia Lin","21");
NewStudent s2 = new NewStudent("Qingyang Feng","18");
NewStudent s3 = new NewStudent("Jiangeng Sun","19");
NewStudent s4 = new NewStudent("Wong Zing", "19");



TreeSet<NewStudent> ts = new TreeSet<NewStudent>();

ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);

for(NewStudent ns: ts){
System.out.println(ns);
}


}
}

247.比较器Comparator的使用

Comparable差不多作用。这个是在测试类直接用内部类的形式使用。

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
package TreeSet;

import 存储学生对象并遍历.Student;

import java.util.Comparator;
import java.util.TreeSet;

public class ComparatorDemo {
public static void main(String[] args) {
TreeSet<NewStudent> ts = new TreeSet<NewStudent>(new Comparator<NewStudent>() {
@Override
public int compare(NewStudent s1, NewStudent s2) {
int s1Age = Integer.parseInt(s1.getAge());
int s2Age = Integer.parseInt(s2.getAge());
int num1 = s1Age - s2Age;
int num2 = num1 == 0? s1.getName().compareTo(s2.getName()):num1;
return num2;
}
});


NewStudent s1 = new NewStudent("Qingxia Lin","21");
NewStudent s2 = new NewStudent("Qingyang Feng","18");
NewStudent s3 = new NewStudent("Jiangeng Sun","19");
NewStudent s4 = new NewStudent("Wong Zing", "19");
NewStudent s5 = new NewStudent("Wong Zing", "19");



ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);

for(NewStudent ns: ts){
System.out.println(ns);
}
}
}

小结: 比较和比较器用来比较包装好的对象比较好用。基本类型比较(比如int数组中元素排序)还是用sort排好一点。

248.成绩排序

对小学生(名字语文成绩数学成绩)进行排序。需求:总分由高到低。

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
package 成绩排序;

public class Student implements Comparable<Student> {
// 成员变量

private String name;
private int ChineseScore;
private int MathScore;

public Student(String name, int chineseScore, int mathScore) {
this.name = name;
ChineseScore = chineseScore;
MathScore = mathScore;
}

public Student() {
}

;

public String getName() {
return name;
}

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

public int getChineseScore() {
return ChineseScore;
}

public void setChineseScore(int chineseScore) {
ChineseScore = chineseScore;
}

public int getMathScore() {
return MathScore;
}

public void setMathScore(int mathScore) {
MathScore = mathScore;
}

@Override
public int compareTo(Student s) {

int STotal = s.ChineseScore + s.MathScore;
int ThisTotal = this.ChineseScore + this.MathScore;
int num = STotal - ThisTotal;
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}

@Override
public String toString() {
return "姓名" + getName() + ", 语文成绩为" + getChineseScore() + ", 数学成绩为" + getMathScore() + ", 总分为" + (getChineseScore() + getMathScore());

}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Student student = (Student) o;

return name != null ? name.equals(student.name) : student.name == null;
}

@Override
public int hashCode() {
return name != null ? name.hashCode() : 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
32
33
34
35
36
37
38
39
40
package 成绩排序;

import java.util.HashSet;
import java.util.TreeSet;

public class ScoreSort {
public static void main(String[] args) {
Student s1 = new Student("Jiangeng Sun", 112,150);
Student s2 = new Student("Wong Zing", 150,130);
Student s3 = new Student("Weihan Li", 150,150);
Student s4 = new Student("Jitong Shi", 130,150);
Student s5 = new Student("Jitong Shi", 130,150);
Student s6 = new Student("Jitong Shi", 129,140);


TreeSet<Student> treeSet = new TreeSet<>();
// 如果重复添加同名数据,可以用hashSet过滤。
// 过滤前
HashSet<Student> hashSet = new HashSet<>();
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(s4);
hashSet.add(s5);
hashSet.add(s6);
for(Student s: hashSet){
System.out.println(s);
treeSet.add(s);
}
System.out.println("-------------------");
// 过滤后再用treeSet排序

for(Student s: treeSet){
System.out.println(s);
}


}
}

总结:为了输出好看,重写了toString方法。为了过滤掉重复添加一个人元素,重写了hashCode方法和equals()方法,并且使用HashSet过滤了一遍。

249. 不重复的随机数

需求:输出十个不同的1-20的随机数。

用的Math.random写的,老师用的Random r创建对象。核心思想不变。

也可以用TreeSet生成,生成后会排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package 十个随机数;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class TenRandom {
public static void main(String[] args) {
boolean flag = true;
Set<Integer> set = new HashSet<Integer>();
while (flag) {
int num = (int) (Math.random() * 20 + 1);
set.add(num);
int size = set.size();
if (size == 10) {
flag = false;
}

}
System.out.println(set);
}
}

250. 泛型概述和好处

这个就是泛型<>

泛型的好处:

  1. 把运行时的error提前到了编译期间。
  2. 避免了强制类型转换。

251. 泛型类

用处:想用一个方法接收很多类型的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Generic;

public class Student<T> {
private T t;

public T getT() {
return t;
}

public void setT(T t) {
this.t = t;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package Generic;

public class test {
public static void main(String[] args) {
Student<String> s = new Student<String>();

s.setT("名字");

Student<Integer> s1 = new Student<Integer>();

s1.setT(21);

System.out.println(s.getT()+","+s1.getT());


}
}

252. 泛型方法

可以在创建对象的时候不定义泛型,但是在调用实际方法的时候定义泛型。

1
2
3
4
5
6
7
8
9
10
package Generic;

public class GenericStudent{

public <T> void show(T t){
System.out.println(t);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package Generic;

public class test {
public static void main(String[] args) {
GenericStudent genericStudent = new GenericStudent();
genericStudent.show("String类型");
genericStudent.show(20);
genericStudent.show(20.12);
genericStudent.show(false);


}
}

253. 泛型接口

定义格式:public interface Generic <T>{}

1
2
3
4
5
6
package 泛型接口;

public interface Generic<T> {
public void show(T t);
}

1
2
3
4
5
6
7
8
9
package 泛型接口;

public class GenericImplement<T> implements Generic<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package 泛型接口;

public class test {
public static void main(String[] args) {
GenericImplement<String> GI = new GenericImplement<String>();

GI.show("林青霞");

GenericImplement<Object> GI2 = new GenericImplement<Object>();

GI2.show("林青霞");
GI2.show(30);

}
}

254. 类型通配符

类型的家族: Object \rightarrow Number \rightarrow Integer

<? extends Number> 决定了上限, <? super Number>决定了下限。

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
package 类型通配符;

import java.util.ArrayList;
import java.util.List;

public class GenericDemo {
public static void main(String[] args) {
List<?> l = new ArrayList<Object>();
List<?> l2 = new ArrayList<Number>();
List<?> l3 = new ArrayList<Integer>();


// List<? extends Number> l4 = new ArrayList<Object>();
List<? extends Number> l5 = new ArrayList<Number>();
List<? extends Number> l6 = new ArrayList<Integer>();

List<? super Number> l7 = new ArrayList<Object>();
List<? super Number> l8 = new ArrayList<Number>();
// List<? super Number> l9 = new ArrayList<Integer>();

// l.add("2");

}
}


255. 可变参数

方法中的参数的数量可变。本质上是把参数们分封装到一个数组中。

格式:public static int sun(int...a){};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package 可变参数;

public class ArgsDemo01 {
public static void main(String[] args) {
System.out.println(sum(10,20));
System.out.println(sum(10,20,30));
System.out.println(sum(10,20,30,40));
System.out.println(sum(10,20,30,40,50));

System.out.println(sum(10));
System.out.println(sum());

}

public static int sum(int... a) {
int sum = 0;
for (int num : a) {
sum += num;
}
return sum;
}
}

注意:一个方法如果有多个参数(单一的参数和可变参数并存),可变参数要放到后面,用逗号隔开。

256. 可变参数的使用

  1. Arrays工具类中有一个静态方法: asList(T... a ): 返回由指定数组支持的固定大小的列表。
  2. List接口中有一个静态方法:of(E... elements):返回包含任意数量元素的不可变列表。
  3. Set接口中有一个静态方法:of(E... elements):返回一个包含任意数量元素的不可变集合。

注意:

正常用list集合的话是创建list对象(使用ArrayList),然后add()。使用asList(可变参数)生成的列表,无法增删!但是可以修改。

通过List.of创建的列表,无法增删修改

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
37
package 可变参数的使用;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

public class ArgsDemo {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello","world","java");

//list.add("javaee"); //UnsupportedOperationException
//list.remove("hello"); //UnsupportedOperationException
list.set(0,"hi");
System.out.println(list);




List<String>list2 = List.of("hello","world","java","java");
// list2.add("java"); // UnsupportedOperationException
//list2.remove("hello"); //UnsupportedOperationException

//list2.set(0,"hi");//UnsupportedOperationException

// Set<String> set = Set.of("hello","world","java","world"); //IllegalArgumentException
Set<String> set = Set.of("hello","world","java");

// set.add("javaee"); //UnsupportedOperationException
// set.remove("javaee"); //UnsupportedOperationException
// set集合没有带索引的方法,没有set方法。




}
}