第一章 List集合
1.1 List接口介绍
java.util.List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会给将实现了List接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性的方式进行存储的,在程序中可以通过索引来访问集合中的指定的元素。此外,List集合还有一个特点就是有序,即元素的存入顺序和取出顺序一致。
- List接口特点:
- 是一个元素存取有序的集合。
- 是一个带有索引的集合。
- 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复元素。
1.2 List接口中常用的方法
List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:
- public void add(int index, E element):将指定的元素,添加到该集合中的指定位置上。
- public E get(int index):返回集合中指定位置的元素。
- public E remove(int index):移除列表中指定位置的元素,返回的是被移除的元素。
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值为被替换的元素。
代码如下:
/*
* java。util.list接口 extends Collection接口
* List接口的特点:
* 1、有序的集合,存储元素和取出元素的顺序是一致的。
* 2、有索引,包含了一些带索引的方法。
* 3、允许存储重复的元素
*
* List接口中带索引的方法:
* public void add(int index, E element):将指定元素明天驾到指定位置上。
* public E get(int index):返回集合中指定位置的元素。
* public E remove(int index):移除列表中指定位置的元素,返回值是被移除的元素。
* public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值为更新的元素。
* 注意:
* 操作索引的时候,一定要防止索引的越界异常。
*
* */import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class Demo01List {public static void main(String[] args) {// 创建一个List集合对象,多态List<String> list = new ArrayList<>();// 使用add方法往集合中添加元素list.add("a");list.add("b");list.add("c");list.add("a");// 打印集合System.out.println(list);// public void add(int index, E element):将指定元素明天驾到指定位置上。// 在c和d之间添加一个指定元素list.add(3, "tiger");System.out.println(list);// public E get(int index):返回集合中指定位置的元素。// 遍历指定集合// 使用普通的for循环for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}// 使用foreachfor (String i: list) {System.out.println(i);}// 使用迭代器Iterator<String> it = list.iterator();while (it.hasNext()) {System.out.println(it.next());}// public E remove(int index):移除列表中指定位置的元素,返回值是被移除的元素。String removeE = list.remove(2);System.out.println("被移除的元素是:" + removeE);System.out.println(list);// public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值为更新的元素。// 把最后一个a替换成为AString setE = list.set(3, "A");System.out.println("被替换的元素:" + setE);System.out.println(list);}
}
第二章 List的子类
2.1 ArrayList集合
java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据,遍历数据,所以ArrayList是最常用的集合。
2.2 LinkedList集合
- java.util.LinkList 集合数据存储结构是链表结构。方便添加元素,删除元素。
- LinkedList 是一个双向链表,结构如下:
在实际的开发过程中对一个集合元素的添加与删除操作经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。如下:
- public void addFirst(E e):将指定元素插入到此列表的开头。
- public void addLast(E e):将指定元素添加到此列表的结尾。
- public E getFirst():返回此列表的第一个元素。
- public E getLast():返回此列表的最后一个元素。
- public E removeFirst():移除并返回此列表的第一个元素。
- public E removeLast():移除并返回此列表的最后一个元素。
- public void push(E e):将元素推入此列表所表示的堆栈。
- public boolean isEmpty():如果列表不包含元素,则返回true。
代码如下:
package com.it.day03code.List;/*
* java.util.LinkedList集合 implements List接口
* LinkedList集合的特点:
* 1、底层是一个链表结构,查询慢,增删快,
* 2、里边包含了大量操作首尾元素的方法。
* 注意:使用LinkList集合特有的方法,不能使用多态。
* public void addFirst():将指定元素插入此列表的开头。
* public E getFirst():返回此列表的第一个元素。
* public E getLast():返回此列表的最后一个元素。
* public E removeFirst():移除并返回此列表的第一个元素。
* public E removeLast():移除并返回此列表的最后一个元素。
* public E pop():从此列表所表示的堆栈处弹出一个元素。
* public void push(E e):将元素推入此列表所表示的堆栈。
* public boolean isEmpty():如果列表不包含元素,则返回true。
*
*
* */import java.util.LinkedList;public class Demo02LinkedList {public static void main(String[] args) {// show01();// show02();show03();}// public E removeFirst():移除并返回此列表的第一个元素。// public E removeLast():移除并返回此列表的最后一个元素。private static void show03() {// 创建LinkedList集合对象LinkedList<String> linked = new LinkedList<>();// 使用add方法往集合中添加元素linked.add("a");linked.add("b");linked.add("c");System.out.println(linked);// String first = linked.removeFirst();String first = linked.pop();System.out.println("移除第一个元素:" + first);String last = linked.removeLast();System.out.println("移除最后一个元素:" + last);System.out.println(linked);}// public E getFirst():返回此列表的第一个元素。// public E getLast():返回此列表的最后一个元素。private static void show02() {// 创建LinkedList集合对象LinkedList<String> linked = new LinkedList<>();// 使用add方法往集合中添加元素linked.add("a");linked.add("b");linked.add("c");linked.clear(); // 清空集合中的元素,在获取集合中的元素会抛出NoSuchElementException// public boolean isEmpty():如果列表不包含元素,则返回true。if (!linked.isEmpty()) {String first = linked.getFirst();System.out.println(first);String last = linked.getLast();System.out.println(last);}}private static void show01() {// 创建LinkedList集合对象LinkedList<String> linked = new LinkedList<>();// 使用add方法往集合中添加元素linked.add("a");linked.add("b");linked.add("c");System.out.println(linked);// // public void addFirst():将指定元素插入此列表的开头。// public void push(E e):将元素推入此列表所表示的堆栈。// 两个方法等效// linked.addFirst("www");linked.push("www");System.out.println(linked);// public E getFirst():返回此列表的第一个元素。// 两个方法等效// linked.addLast("com");linked.add("com");System.out.println(linked);}}
第四章 Set接口
java.util.Set接口和java.util.List 接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection进行扩充,只是比Collection接口更加的严格,与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
4.1 HashSet集合
- java.util.HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致),java.util.HashSet底层实现其实是一个java.util.HashMap支持。
- HashSet是根据对象的哈希值来确定元素在集合中的存储位置因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode和equals方法
- 代码如下:
public class Demo01HashCode {public static void main(String[] args) {// Person类继承了Object类,所以可以使用Object类的hashCode方法Person p1 = new Person();int h1 = p1.hashCode();System.out.println(h1);Person p2 = new Person();int h2 = p2.hashCode();System.out.println(h2);System.out.println(p1);System.out.println(p2);System.out.println(p1 == p2); // false// String类的哈希值// String类重写了Object类的hashCode方法。String s1 = new String("abc");String s2 = new String("abc");System.out.println(s1.hashCode());System.out.println(s2.hashCode());}
}
4.2 HashSet集合存储数据的结构(哈希表)
- 哈希表:在jdk1.8之前,哈希表底层是采用数组+链表实现,即使用链表处理冲突同一个hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多,通过key值依次查找的效率较低,所以在jdk1.8之后,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阀值(8)时,将链表转换为红黑树,这样提高了查找的效率。如下图:
4.3 HashSet存储自定义类型元素
给HashSet中存放自定义元素时,需要同时重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一,代码如下:
创建一个自定义类:
package com.it.day03code.hashCode;import java.util.Objects;public class Person extends Object {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age &&Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
定义测试类:
/*
* HashSet存储自定义类型元素:
* set集合报错元素唯一:
* 存储的元素(String,Integer,...,Student,Person...),必须重写hashCode方法和equals方法
*
* 要求:
* 同名和同年龄的人,视为同一个人只能存储一次
*
* */import java.util.HashSet;public class Demo03HashCodeSetSavePerson {public static void main(String[] args) {// 创建HashSet集合存储PersonHashSet<Person> set = new HashSet<>();Person p1 = new Person("小美女", 18);Person p2 = new Person("小美女", 18);Person p3 = new Person("小美女", 19);System.out.println(p1.hashCode());System.out.println(p2.hashCode());System.out.println(p1 == p2);System.out.println(p1.equals(p2));set.add(p1);set.add(p2);set.add(p3);System.out.println(set);}}
4.4 LinkedHashSet
我们知道HashSet保证元素唯一,可以元素存储却是没有顺序的,要保证有序,我们可以使用HashSet下的一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。代码如下:
/*
* java.util.LinkedHashSet集合 extends HashSet集合
* LinkedHashSet集合:
* 底层是一个哈希表(数组+链表结构/ 红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序
*
* */import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;public class Demo04LinkedHashSet {public static void main(String[] args) {HashSet<String> set = new HashSet<>();set.add("www");set.add("abc");set.add("abc");set.add("itcast");System.out.println(set); // 无序的,不允许重复LinkedHashSet<String> linked = new LinkedHashSet<>();linked.add("www");linked.add("abc");linked.add("abc");linked.add("itcast");System.out.println(linked); // 有序,不允许重复}
}
4.5 可变参数
在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数的类型一致,我们可以将其简化成如下格式:
修饰符 返回值类型 方法名(参数类型...形参名){ }
其实这个书写完全等价于
修饰符 返回值类型 方法名(参数类型[] 形参名){ }
后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。
代码如下:
/*
* 可变参数:是JDK1.5之后出现的新特性
* 使用前提:
* 当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数。
* 使用格式:定义方法时使用
* 修饰符 返回值类型 方法名(数据类型...变量名) { }
* 可变参数的原理:
* 可变参数的底层就是一个数组,根据传递参数个数的不同,会创建不同长度的数组,来存储这些参数
* 传递的参数个数,可以是0哥(不传递),1,2,3,多个
*
* 注意事项:
* 1、一个方法的参数列表,只能有一个可变参数。
* 2、如果方法的参数有多个,那么可变参数必须写在参数列表的末尾。
*
* 可变参数的终极写法:
* public static void method(Object...obj),可以传入任意对象
* */public class Demo01VarArgs {public static void main(String[] args) {int i = add();// System.out.println(i);int sum = add(12, 3, 4, 8);System.out.println(sum);}// 定义0-n个整数和的方法// 已知计算整数的和,数据类型已经确定int// 但是参数的个数不确定,不知道要计算几个整数的和,就可以使用可变参数public static int add(int...arr) {// System.out.println(arr); // 底层是一个数组,数组的长度就是传参的个数// System.out.println(arr.length);int sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}return sum;}}
第五章 Collections
5.1 常用功能
- java.utils.Collections是集合工具类,用来对集合对象进行操作,部分方法如下:
- public static <T> boolean addAll(Collection<T> c, T...elements):往集合中添加一些元素。
- public static void shuffle(List<?> list):打乱顺序,打乱集合顺序。
- public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
- public static <T> void sort(List<T> list, Comparator<? super T>):将集合中元素按照指定规则排序。
- 代码如下:
package com.it.day03code.Collections;/*
* java.util.Collections是集合工具类,用来对集合进行操作,部分方法如下:
* public static <T> boolean addAll(Collection<T> c, T... element):往集合中添加一些元素
* public static void shuffle(List<?> list):打乱集合顺序。
*
* */import java.util.ArrayList;
import java.util.Collections;public class Demo01Collections {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();// 往集合中添加元素list.add("a");list.add("b");list.add("c");list.add("d");list.add("e");System.out.println(list);// public static <T> boolean addAll(Collection<T> c, T... element):往集合中添加一些元素Collections.addAll(list, "a", "b", "c", "d", "e");System.out.println(list);// public static void shuffle(List<?> list):打乱集合顺序。Collections.shuffle(list);System.out.println(list);}
}
5.2 Comparator比较器
代码如下:
定义一个类:
public class Person implements Comparable<Person> {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}// 重写排序的规则@Overridepublic int compareTo(Person o) {// return 0; // 认为元素都是相同的// 自定义比较的规则,比较两个人的年龄(this,参数person)// return this.getAge() - o.getAge(); // 年龄升序排序return o.getAge() - this.getAge(); // 年龄降序排序}
}
定义一个测试类:
/*
* java.util.Collections是集合工具类,用来对集合进行操作,部分方法如下:
* public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
*
* 注意:
* sort(List<T> list)使用前提
* 被排序的集合里边存储的元素,必须实现Comparable,重写接口中的方法compareTo定义排序规则。
*
* Comparable接口的排序规则:
* 自己(this) - 参数:升序
* 参数 - 自己:降序
* */import java.util.ArrayList;
import java.util.Collections;public class Demo02Sort {public static void main(String[] args) {ArrayList<Integer> list01 = new ArrayList<>();list01.add(1);list01.add(3);list01.add(2);System.out.println(list01);// public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。Collections.sort(list01);System.out.println(list01);ArrayList<String> list02 = new ArrayList<>();list02.add("a");list02.add("c");list02.add("b");System.out.println(list02);ArrayList<Person> list03 = new ArrayList<>();list03.add(new Person("张三", 18));list03.add(new Person("李四", 20));list03.add(new Person("王五", 15));System.out.println(list03);Collections.sort(list03);System.out.println(list03);}
}
定义一个类:
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
定义一个测试类:
/*
* java.utils.Collections是集合工具类,用来对集合进行操作。部分方法如下:
* public static <T> void sort(List<T> list, Comeparator< ? super T>):将集合中元素按照指定的规则排序。
*
* Comparator和Comparable的区别
* Comparable:自己(this) 和别人(参数)比较,自己需要实现comparable接口,重写比较的规则comparaTo方法
* Comparator:相当于找一个第三方的裁判比较两个
*
* Comparator的排序规则:
* o1 - o2 就是升序
* o2 - o1 就是降序
*
* */import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;public class Demo03Sort {public static void main(String[] args) {ArrayList<Integer> list01 = new ArrayList<>();list01.add(1);list01.add(3);list01.add(2);System.out.println(list01);Collections.sort(list01, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1 - o2; // 前面减后面就是升序,反过来就是降序}});System.out.println(list01);ArrayList<Student> list02 = new ArrayList<>();list02.add(new Student("tiger", 18));list02.add(new Student("trony", 15));list02.add(new Student("hahah", 23));list02.add(new Student("hahah", 18));// 根据年龄升序
// Collections.sort(list02, new Comparator<Student>() {
// @Override
// public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();
// }
// });System.out.println(list02);// 组合比较Collections.sort(list02, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 按照年龄升序排序int result = o1.getAge() - o2.getAge();// 如果两个人年龄相同,再使用姓名的第一个字母比较if (result == 0) {result = o1.getName().charAt(0) - o2.getName().charAt(0);}return result;}});System.out.println(list02);}}
5.3 Comparable和Comparator两个接口的区别
- Comparable:强行对实现它的每一个类的对象进行排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法。只能在类中实现compareTo()方法一次,不能经常修改类的代码实现自己想要的排序,实现此接口的对象列表(和数组)可以通过COllections.sort(和Array.sort)进行自动排序。对象可以作用有序映射中的键或有序集合中的元素,无序指定比较器。
- Comparator:强行对某个对象整体排序,可以将Comparator传递给sort方法(如COllection.sort或Array.sort),从而允许在排序顺序上实现精确的控制,还可以使用Comeparator来控制某些数据结构的顺序,或者为那些没有自然顺序的对象collection提供排序。
5.4 Comparator扩展
代码如下:
定义一个Student类:
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
定义一个测试类:
/*
* java.utils.Collections是集合工具类,用来对集合进行操作。部分方法如下:
* public static <T> void sort(List<T> list, Comeparator< ? super T>):将集合中元素按照指定的规则排序。
*
* Comparator和Comparable的区别
* Comparable:自己(this) 和别人(参数)比较,自己需要实现comparable接口,重写比较的规则comparaTo方法
* Comparator:相当于找一个第三方的裁判比较两个
*
* Comparator的排序规则:
* o1 - o2 就是升序
* o2 - o1 就是降序
*
* */import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;public class Demo03Sort {public static void main(String[] args) {ArrayList<Integer> list01 = new ArrayList<>();list01.add(1);list01.add(3);list01.add(2);System.out.println(list01);Collections.sort(list01, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1 - o2; // 前面减后面就是升序,反过来就是降序}});System.out.println(list01);ArrayList<Student> list02 = new ArrayList<>();list02.add(new Student("tiger", 18));list02.add(new Student("trony", 15));list02.add(new Student("hahah", 23));list02.add(new Student("hahah", 18));// 根据年龄升序
// Collections.sort(list02, new Comparator<Student>() {
// @Override
// public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();
// }
// });System.out.println(list02);// 组合比较Collections.sort(list02, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 按照年龄升序排序int result = o1.getAge() - o2.getAge();// 如果两个人年龄相同,再使用姓名的第一个字母比较if (result == 0) {result = o1.getName().charAt(0) - o2.getName().charAt(0);}return result;}});System.out.println(list02);}}