法–傻瓜笔记–1123(第七章:集合/容器)
袁永豪 2020-11-25 21:35:26 41 收藏 2
分类专栏: 笔记 文章标签: java
版权
第七章:集合/容器
集合:能动态增长长度,并且可以实现各种数据结构的容器,就是集合。
Java的集合框架是由很多接口、抽象类、具体类组成的,都位于java.util包中
1.Collection接口
数组的缺点: 长度一旦定义就不可变 , 结构单一 ,只存储类型相同的元素
Collection(集合接口):不能实例化 集合可以存储引用类型(默认是Object类型),可以添加任何元素,它会先用valueOf()自动装箱,最好还是向集合中添加同一类型的元素
1.基本方法
public static void main(String[] args) {
// 通过子类创建父类对象
Collection c = new ArrayList();
// 向末尾添加元素
c.add(2);
c.add("3");
c.add(4);
c.add(3);
c.add("6");
c.add(true);// 它会先用valueOf()自动装箱
System.out.println(c);
// 删除指定元素,并且删除时需要与输入时的数据类型相同
c.remove("3");
System.out.println(c);
// size()方法 得到集合的长度
// length属性 得到数组的长度
// length()方法 得到字符串的长度
System.out.println(c.size());
// isEmpty 是否为空
System.out.println(c.isEmpty());
// contains 是否包含
System.out.println(c.contains(3));
// clear 清空
// c.clear();
// System.out.println©;
// addAll 将一个集合添加到另一个集合中
Collection c1 = new ArrayList();
c1.add(7);
c1.add(8);
c1.add(9);
c1.addAll(c);
System.out.println(c1);
// containsAll 集合 c1 是否包含集合 c
System.out.println(c1.containsAll(c));
// removeAll 删除集合c1中与c相同的元素
// c1.removeAll©;
// System.out.println(c1);
// retainAll c1中只保留c1与c的交集,有改变时返回true
System.out.println(c1.retainAll(c));
System.out.println(c1);
// removeIf有选择地删除指定元素 匿名内部类过滤
System.out.println(c1.removeIf(new Predicate() {
@Override
public boolean test(Object o) {
return o.equals("6");
}
}));
}
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
2.集合转数组 toArray( )
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(“1”);
c.add(“2”);
c.add(“3”);
c.add(“4”);
// 第一种方式
Object obj = c.toArray();
System.out.println(obj.toString());
// 第二种方式
Collection<String> c1 = new ArrayList<String>();// JDK8以后如果前面写了,后面就不用写了。
c1.add("5");
c1.add("6");
c1.add("7");
c1.add("8");
String[] s = c1.toArray(new String[c1.size()]);
System.out.println(Arrays.toString(s));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3.数组转集合 asList(T… a)
public static void main(String[] args) {
// asList(T…a)数组转换列表
Integer[] i = new Integer[]{1,2,4};
List list = Arrays.asList(i);
System.out.println(list);
// 可变长度参数,可同时传入多个参数
// 本质是一个数组,一个参数列表只能有一个
// 必须方法参数列表末尾,可以直接传一个数组。
test(1,2,3,4);
}
public static void test(int...a){
System.out.println("");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
4.特殊方法 sort( ),subList( ),removeRange( )
public static void main(String[] args) {
ArrayList a = new ArrayList();
a.add(“s”);
a.add(“d”);
a.add(“f”);
a.add(“a”);
a.add(“t”);
a.add(“k”);
// 不能直接使用sort函数,需要创建一个比较类
a.sort(new StringC());
System.out.println(a);
// 从集合中截取元素,包括开始,不包括结束
System.out.println(a.subList(2,5));
// 删除指定区间元素 包含开始,不包含结束
CollectionDemo3 list = new CollectionDemo3();
list.add("s");
list.add("d");
list.add("f");
list.add("a");
list.add("t");
list.add("k");
list.removeRange(0,3);
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
排序所需要的比较类
public class StringC implements Comparator {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
}
1
2
3
4
5
6
2.List接口
List:数据对象 有顺序 且 可以重复。
List继承了Collection接口,有三个实现的类,分别是下面的三个:
LinkedList:采用双向链表存储方式。插入、删除元素时效率比较高
Vector: 数组列表,同步锁,线程安全的,两倍扩容
ArrayList: 数组列表,数据采用数组方式存储,实现了长度可变的数组,一点五倍扩容。遍历元素与随机访问元素效率高。
1.ArrayList
ArrayList: 数组列表,数据采用数组方式存储,实现了长度可变的数组,一点五倍扩容。
在内存中分配连续的空间。遍历元素和随机访问元素的效率比较高。(是我们最常用的)
public static void main(String[] args) {
// ArrayList的默认空间初始值是10,如果需要更大的空间,建议在一开始初始化的时候就设置新的空间大小。
// ArrayList的常用方法
ArrayList a1 = new ArrayList(100);
a1.add(0,1);
a1.add(1,3);
a1.add(0,2);
a1.add(1,4);
a1.add(3,4);
a1.add(3,2);
a1.add(9);// 不加索引就是向末尾插入
System.out.println(a1);// [2, 4, 1, 3]
// 测试之前add()方法是赋值的意思,结果出来之后知道了,是以插入的方法进行赋值
// get()方法是通过指定index索引得到数组元素
System.out.println(a1.get(0));// 4
// indexOf方法是 从头遍历寻找指定元素的索引值
// 如果搜索的是数组中没有的值,那么会返回 -1
// 如果有重复的元素,会返回距离头部最近的元素的索引
System.out.println(a1.indexOf(4));
// lastIndexOf 从尾遍历寻找指定元素的索引值
// 如果搜索的是数组中没有的值,那么会返回 -1
// 如果有重复的元素,会返回距离尾部最近的元素的索引
System.out.println(a1.lastIndexOf(2));
// remove 删除并返回指定位置的元素
// 如果超过索引范围,就会抛出异常java.lang.IndexOutOfBoundsException
System.out.println(a1.remove(2));
System.out.println(a1);// [2, 4, 2, 4, 3]
// set 修改指定索引的元素值
// 如果超过索引范围,就会抛出异常java.lang.IndexOutOfBoundsException
a1.set(3,9);
System.out.println(a1);// [2, 4, 2, 9, 3]
}
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
2.LinkedList
LinkedList:采用双向链表存储方式。插入、删除元素时效率比较高
public static void main(String[] args) {
LinkedList a = new LinkedList();
// add 向指定索引处插入元素
a.add(0,1);
a.add(1,2);
a.add(2,3);
a.add(1,4);
a.add(4,5);
System.out.println(a);// [1, 4, 2, 3, 5]
// addFirst 向头部插入指定元素
a.addFirst(3);
a.addFirst(0);
System.out.println(a);// [0, 3, 1, 4, 2, 3, 5]
// addLast 向尾部插入指定元素
a.addLast(9);
a.addLast(10);
System.out.println(a);// [0, 3, 1, 4, 2, 3, 5, 9, 10]
// remove 删除指定索引的元素
// 超出索引位置会报错java.lang.IndexOutOfBoundsException
a.remove(7);
System.out.println(a);// [0, 3, 1, 4, 2, 3, 5, 10]
// removeFirt 删除头部首个元素
a.removeFirst();
System.out.println(a);// [3, 1, 4, 2, 3, 5, 10]
// removeLast 删除尾部首个元素
a.removeLast();
System.out.println(a);// [3, 1, 4, 2, 3, 5]
// getFirst 获得头部的首个元素
System.out.println(a.getFirst());// 3
// getLast 获得尾部的首个元素
System.out.println(a.getLast());// 5
// 因为LinkedList 和 ArrayList实现了同一个接口List所以能调用的方法基本是一样的
System.out.println(a.get(2));// 4
}
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
3.Vector
vector: 底层也是数组实现的,可扩容,,多线程安全。(方法基本与ArrayList一样)
Vector v = new Vector<>();
v.add(“1”);
v.add(“3”);
v.add(“2”);
v.add(“2”);
v.add(“4”);
System.out.println(v);//[1, 3, 2, 2, 4]
1
2
3
4
5
6
7
4.集合遍历
集合遍历:
for循环
foreach循环
iterator迭代器
public static void main(String[] args) {
Vector v = new Vector<>();
v.add(“1”);
v.add(“3”);
v.add(“2”);
v.add(“2”);
v.add(“4”);
System.out.println(v);//[1, 3, 2, 2, 4]
// 集合迭代与遍历
// for循环遍历
for (int i = 0; i < v.size(); i++) {
System.out.print(v.get(i));// 1324
if(v.get(i).equals("2")){
v.remove(i);
/*
* 删除元素后,长度减一,元素向前移动一位。
* 想解决这个问题,可以在执行完删除操作后,i--
* */
i--;
}
}
System.out.println();
System.out.println(v);// [1, 3, 4]
// foreach 遍历
for(String vector : v){
System.out.print(vector);// 遍历
if(vector.equals("3")){
v.remove(vector);
break;
/*
* 如果删除元素就会抛出异常,即不允许在遍历过程中进行操作。
* ConcurrentModificationException 表明不能修改
* 如果必要进行删除,可以在删除元素后立即退出循环,这样就不会抛出异常。
* */
}
}
System.out.println();
System.out.println(v);// [1, 4]
// 迭代器 Iterator ——> 接口
Iterator<String> iterator = v.iterator();
while(iterator.hasNext()){// 是否还有元素
String s = iterator.next();
System.out.println(s);// 遍历
iterator.remove();// 拿一个删除一个
// 必须使用Iterator专用删除方法,无需参数,不然也会抛出异常
// 删除指定元素
// if(iterator.equals(“1”)){
// iterator.remove();
// }
}
}
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
3.泛型
泛型:早期的Object类可以表示接收任何类型,但是在类型转换时,存在一定的隐患,因此出现了泛型
泛型类型可以添加任何元素,但只能是引用类型,例:Integer
泛型类型默认是 Object类型
泛型可以有多个,例如 在类声明时
/*
-
泛型:早期的Object类可以表示接收任何类型,但是在类型转换时,存在一定的隐患,因此出现了泛型
-
泛型类型可以添加任何元素,但只能是引用类型,例:Integer
-
泛型类型默认是 Object类型
-
泛型可以有多个,例如 在类声明时
-
*/
public class GenericDemo {
// 泛型在类声明中使用,可以是多个,例:<T,V,K>
Object obj;public static void main(String[] args) {
// 向上转型,没问题,但是向下转型可能会有问题
GenericDemo generic = new GenericDemo();
generic.obj = 1;
generic.obj = “1”;
generic.obj = true;ArrayList arr = new ArrayList(); arr.add(1); arr.add("2"); arr.add(true); for (int i = 0; i < arr.size(); i++) { Object obj = arr.get(i);// 这样是没问题的 System.out.print(obj);// 1, 2, true } System.out.println(); for (int i = 0; i < arr.size(); i++) { // String s = arr.get(i); /* * 这样会直接编译报错, * 因为String类与Integer类和Boolean类都是Object类的子类, * 但是他们之间没有关联,是"平级的" * 因此会编译失败 * */ // 这种时候还想要遍历的话就需要加一个判断 // 但是当一个集合中的数据类型过多的时候,这就会很麻烦 Object obj = arr.get(i); if (obj instanceof String) { String s1 = (String) obj; System.out.println(s1); } } // 如果使用泛型的话就会直接确定集合元素的类型 ArrayList<String> alist = new ArrayList<String>(); // JDK-8 以后可以不用再写后面的类型 // 类型不对的话,会在添加元素编译的时候直接报错 // alist.add(1); // alist.add(true); alist.add("1"); alist.add("2"); alist.add("3"); for (int i = 0; i < alist.size(); i++) { System.out.print(alist.get(i)); }
}
// 泛型在方法中使用
public T test(T t1) {
return t1;
}
}
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
4.Set接口
Set:接口,不允许重复元素
HashSet:无序(不是按照添加顺序排序,而是按照哈希值排序),不可重复
TreeSet:有序(按照元素的自然顺序存储,例如2,1,3——> 1,2,3)不可重复。数据类型必须 实现comparable接口 , 重写compareTo()
1.HashSet
hashSet:无序(不是按照添加顺序排序,而是按照哈希值排序),不可重复
哈希表加链表存储,同一位置可以存储不同内容的元素
底层为hashMap
public native hashcode(),native 意为调用本地系统方法
public static void main(String[] args) {
Student s1 = new Student(1,“jim1”);
Student s2 = new Student(2,“jim1”);
Student s3 = new Student(3,“jim1”);
Student s4 = new Student(4,“jim4”);
// 添加时根据内容的hash值,再经过hash函数计算得到元素在hash表中存储的位置
HashSet hashSet = new HashSet();
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
hashSet.add(s4);
// 如果不在student类中重写hashcode(),那么就会调用Object中hashcode()方法算出对象(对象不同,哈希值就不同)的哈希值
// 重写Object类中hashCode(),来自己根据对象中包含的内容计算hash值。
// 向hashSet中添加元素是如何判断重复元素?
// 底层是双保险,既要提高判断效率,又要安全可靠。
/*
* ① 首先通过hashcode()算出添加内容的哈希值,判断hash值在集合中是否存在,
* 但是有时哈希值可能相同,但内容不同,因此并不安全
* 效率高,但是可能会出现重复
* ② 当哈希值相同时,就需要通过equals()足逐个判断元素内容是否相同。
* 效率底,安全
* */
System.out.println(hashSet);
}
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
Student类
public class Student {
private int num;
private String name;
public Student(int num, String name) {
this.num = num;
this.name = name;
}
public Student() {
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Student student = (Student) o;
return num == student.num &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(num,name);
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
}
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
2.TreeSet
TreeSet:有序(按照元素的自然顺序存储,例如2,1,3——> 1,2,3)不可重复
数据类型必须 实现comparable接口 , 重写compareTo( )
底层为红黑树
public static void main(String[] args) {
TreeSet tset = new TreeSet();
tset.add(“c”);
tset.add(“d”);
tset.add(“b”);
tset.add(“a”);
System.out.println(tset);//[a, b, c, d] 有序,按照内容的自然顺序排序
// 自定义对象
Student s1 = new Student(1,"stu1");
Student s2 = new Student(2,"stu2");
Student s3 = new Student(3,"stu3");
Student s4 = new Student(4,"stu1");
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
// 自己定义的数据类型如果不实现comparable接口,并重写compareTo(),就会报错
// java.lang.ClassCastException
System.out.println(ts);
}