2019-01-01
2019-01-01 本文已影响2人
DreamPath
基于List、Set集合,及工具类Collections集合元素排序整理
List集合
1.1 List集合介绍
java.util.List 接口继承自 Collection 接口,是单列集合的一个重要分支。
-
存储形式:线性存储
-
集合特点:
- 元素存取有序。
- 带索引,通过索引就可操作元素。
- 元素可重复。
1.2 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) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
package list_demo;
import java.util.ArrayList;
import java.util.List;
/**
* @author lx
* @date 2018/12/30 - 13:12
* public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
* public E get(int index) :返回集合中指定位置的元素。
* public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
* public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素
*/
public class List_Demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
list.add("Hello World");
// 在索引为1的位置添加元素"你好"
list.add(1, "你好");
System.out.println(list);//[Hello, 你好, World, Hello World]
// 返回集合中指定位置的元素。
System.out.println(list.get(2));//World
//删除元素(通过内容,通过索引)
list.remove("Hello");
// list.remove(0);
System.out.println(list);//[你好, World, Hello World]
// 在指定索引处替换元素
list.set(2, "你好世界");
System.out.println(list);//[你好, World, 你好世界]
}
}
List的子类
ArrayList集合
java.util.ArrayList 集合数据存储的结构是数组结构。
- 特点:
元素增删慢,查找快。
多用于查询数据,遍历数组
LinkedList集合
java.util.LinkedList 集合数据存储结构是(双向)链表结构。
图片.png- LinkedList常用方法及其用法
package list_demo;
import java.util.LinkedList;
/**
* @author lx
* @date 2018/12/30 - 13:33
* public void addFirst(E e) :将指定元素插入此列表的开头。
* public void addLast(E e) :将指定元素添加到此列表的结尾。
* public E getFirst() :返回此列表的第一个元素。
* public E getLast() :返回此列表的后一个元素。
* public E removeFirst() :移除并返回此列表的第一个元素。
* public E removeLast() :移除并返回此列表的后一个元素。
* public E pop() :从此列表所表示的堆栈处弹出一个元素。
* public void push(E e) :将元素推入此列表所表示的堆栈。
* public boolean isEmpty() :如果列表不包含元素,则返回true
*/
public class List_demo1 {
public static void main(String[] args) {
LinkedList<String> strings = new LinkedList<>();
strings.add("赵丽颖");
strings.add("冯绍峰");
strings.add("李连杰");
System.out.println(strings);//[赵丽颖, 冯绍峰, 李连杰]----
//在首尾添加元素
strings.addFirst("马云");
strings.addLast("甑子丹");
System.out.println(strings);//[马云, 赵丽颖, 冯绍峰, 李连杰, 甑子丹]
//直接获取首尾元素
System.out.println(strings.getFirst());//马云
System.out.println(strings.getLast());//甑子丹
//删除首尾元素
strings.removeFirst();
strings.removeLast();
System.out.println(strings);//[赵丽颖, 冯绍峰, 李连杰]
//弹出集合的栈顶元素。(弹栈)打子弹(先打出弹夹上第一个)
String pop = strings.pop();
System.out.println(pop);//赵丽颖
System.out.println(strings);//[冯绍峰, 李连杰]
//将元素推入此列表所表示的堆栈。(压栈存储)放弹夹
strings.push("赵丽颖");
System.out.println(strings);//[赵丽颖, 冯绍峰, 李连杰]
//判断集合中是否含有元素
System.out.println(strings.isEmpty());//false
}
}
Set接口
Set集合的定义
java.util.Set 接口继承自 Collection 接口,只是其中的方法比 Collection 接口更加严格了。
Set 集合特点:
1.无序、不可重复(存储数据唯一,
原因:底层使用了数组加链表的形式存储数据)。
2.查询快,增删快(jdk1.8以后)。
Set接口的子类
- Set 集合的常用子类java.util.HashSet 、 java.util.LinkedHashSet。
HashSet集合
java.util.HashSet 是 Set 接口的一个实现类,它所存储元素是不可重复的,元素都是无序的(即存取顺序不一致)。
- HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。
- 保证元素唯一性的方式依赖于: hashCode 与 equals 方法。
package set_demo;
import java.util.HashSet;
/**
* @author lx
* @date 2018/12/30 - 21:42
*/
public class HashSetDemo {
public static void main(String[] args) {
// 创建HashSet集合
HashSet<String> str = new HashSet<>();
//添加元素
str.add("刘备");
str.add("张飞");
str.add("关羽");
str.add("刘备");//不可重复
//输出集合
System.out.println(str);//[关羽, 张飞, 刘备] 无序排列
}
}
HashSet集合存储数据的结构(哈希表)
- 1.在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。
- 2.但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。查找速度过慢。
- 3.而在JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
- JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一, 其实就是根据对象的hashCode和equals方法来决定的。
- 如果我们往集合中存放自定义的对象,那么保证其唯一, 就必须复写hashCode和equals方法建立属于当前对象的比较方式。
HashSet存储自定义类型元素
- HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
- 自定义Student类
package set_demo;
import java.util.Objects;
/**
* @author lx
* @date 2018/12/31 - 11:34
*/
public class Student {
private String name;
private int age;
private int id;
// 无参构造方法
public Student(){
}
//有参构造方法
public Student(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
//setter,getter方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
//重写equals方法和hashCode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
id == student.id &&
Objects.equals(name, student.name);
}@Override
public int hashCode() {
return Objects.hash(name, age, id);
}
// 重写toString方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
- 创建一个测试类
package set_demo;
import java.util.HashSet;
/**
* @author lx
* @date 2018/12/31 - 11:39
*/
public class HashSet_demo1 {
public static void main(String[] args) {
HashSet<Student> strings = new HashSet<>();
Student student = new Student("梦雨", 19, 1000);
strings.add(student);
//使用匿名对象
strings.add(new Student("小明", 22, 1001));
strings.add(new Student("小雪", 18, 1002));
strings.add(new Student("梦雨", 19, 1000));
//由于重写了toString方法,因此可以直接输出
System.out.println(strings);
//输出结果如下,,明显看出是无序的,不可重复的。
//[Student{name='小明', age=22, id=1001},
// Student{name='小雪', age=18, id=1002},
// Student{name='梦雨', age=19, id=1000}]
}
}
2.3 LinkedHashSet集合
- java.util.LinkedHashSet 是HashSet的一个子类。
也能保证元素的唯一性(不可重复)。 - 而它的数据存储结构是链表和哈希表组合而成的。因此是有序的。
package set_demo;
import java.util.LinkedHashSet;
/**
* @author lx
* @date 2018/12/31 - 11:59
*/
public class LinkedHashSetDemo {
public static void main(String[] args) {
LinkedHashSet<String> strings = new LinkedHashSet<>();
//子类的实例父类的引用(多态)
Set<String> strings1=new LinkedHashSet<>();
strings.add("杨幂");
strings.add("刘恺威");
strings.add("胡歌");
strings.add("霍建华");
strings.add("杨幂");
System.out.println(strings);
/*
输出结果为:[杨幂, 刘恺威, 胡歌, 霍建华]
可以看出集合是有序,不可重复的。
*/
}
}
可变参数
-
在JDK1.5之后,如果我们定义一个类型一致的多个参数时,定义规则为:
- 修饰符 返回值类型 方法名(参数类型... 形参名){ }<==>修饰符 返回值类型 方法名(参数类型[] 形参名){ }.
-
后面这种方式需要传递数组才能完成值传递,而前者只需要直接传递数据即可。
-
可变参数:调用时不创建数组,直接将数组元素传递。
-
编译生成.class文件前直接就将这些元素封装成一个数组,然后再进行传递。
package kebian_CanShu;
/**
* @author lx
* @date 2019/1/1 - 1:24
*/
public class KebianCanShuDemo {
public static void main(String[] args) {
//数组传递
int[] aInt = {1, 2, 3, 4, 5};
int sum=getSum(aInt);
System.out.println(sum);//15
//可变参数 数据值传递
int sum2 = getSum(1,2,4,5,6,7);
System.out.println(sum2);//25
}
//使用可变参数语法: 数据类型 ... 数组名
private static int getSum(int... aInt) {
int sum2 = 0;
for (int s : aInt) {
sum2 += s;
}
return sum2;
}
/* 一般数组传递
private static int getSum(int[] aInt) {
int sum = 0;
for(int a : aInt){
sum += a;
}
return sum;
}*/
}
Collections 工具类
常用方法
package biJiao;
import java.util.*;
/**
* @author lx
* @date 2019/1/1 - 11:44
* 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> ) :将集合中元素按照指定规则排序
*/
public class BiJiaoDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList();
/* list.add(22);
list.add(20);
list.add(17);
list.add(22);
System.out.println(list);*/
//采用工具类 完成 往集合中添加元素
Collections.addAll(list, 2, 5, 6, 7, 9);
// 打乱集合元素顺序
Collections.shuffle(list);
System.out.println(list);//[7, 5, 2, 6, 9]
//将集合中的元素按照默认规则排序(默认升序)
Collections.sort(list);
System.out.println(list);//[2, 5, 6, 7, 9]
}
}
- 字符串默认排序及其自定义排序
package biJiao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* @author lx
* @date 2019/1/1 - 13:17
*/
public class BiJiaoDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("sba");
list.add("aba");
list.add("bbd");
list.add("cer");
list.add("bar");
System.out.println(list);//[sba, aba, bbd, cer, bar]
//字符串默认排序是以首写字母排序的.
// 如果首写字母相同,则比较下一位,按照字母升序排列
Collections.sort(list);
System.out.println(list);//[aba, bar, bbd, cer, sba]
//按照字母降序排序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.charAt(0)-o1.charAt(0);
}
});
System.out.println(list);//[sba, cer, bar, bbd, aba]
}
}
Comparable和Comparator两个接口的区别
Comparable:
- 1.将它的实现类的对象强制进行整体排序,并在类中重写一次compareTo方法。
- 2.不能经常修改类中的代码来实现想要的排序。
- 3.实现此接口的对象列表或者数组可通过Collections.sort()或者Arrays.sort()进行自动排序。
- 4.对象可以用作有序映射中 的键或有序集合中的元素,无需指定比较器。
Comparator:
-
1.强行对某个对象进行整体排序。
-
2.可以将Comparator 传递给工具类中的sort方法,从而允许在排序顺序上实现精确控制。
-
3.使用Comparator来控制某些数据结构(如有序set或 有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。
方法一:采用实现comparable接口
创建一个学生类,存储到ArrayList集合中完成指定排序操作。
package biJiao;
public class Student implements Comparable{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age= age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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;
}
@Override//返回0 相等 正数 降序排列 负数 升序排列
public int compareTo(Object o) {
Student o1 = (Student) o;
return (getAge()-o1.getAge())*(-1);
}
}
创建测试类
package biJiao;
import java.util.ArrayList;
import java.util.Collections;
/**
* @author lx
* @date 2019/1/1 - 15:04
*/
public class Student_demo {
public static void main(String[] args) {
//创建集合
ArrayList<Student> list = new ArrayList<>();
//添加元素
list.add(new Student("马云", 30));
list.add(new Student("宋小宝", 34));
list.add(new Student("宋人喜", 33));
list.add(new Student("史玉柱", 29));
//根据Student类的年龄降序排序
Collections.sort(list);
System.out.println(list); //输出结果如下
//[Student{name='宋小宝', age=34},Student{name='宋人喜', age=33},
//Student{name='马云', age=30}, Student{name='史玉柱', age=29}]
}
}
方法二:采用new Comparator实现
- Student类中只需要不用再实现Comparable接口,也就不用重写compareTo方法
测试类
package biJiao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* @author lx
* @date 2019/1/1 - 15:04
*/
public class Student_demo {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("马云", 30));
list.add(new Student("宋小宝", 34));
list.add(new Student("宋人喜", 33));
list.add(new Student("史玉柱", 30));
//sort方法下做如下改动,Student类中,不再实现comparable接口并不重写compareTo方法
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//年龄降序
int result=o2.getAge()-o1.getAge();
//如果年龄相同,按照名字首写字母降序
if (o1.getAge()==o2.getAge()) {
result= o1.getName().charAt(0)-o2.getName().charAt(0);
}
return result;
}
});
System.out.println(list); //输出结果如下 s m
//[Student{name='宋小宝', age=34}, Student{name='宋人喜', age=33},
// Student{name='史玉柱', age=30}, Student{name='马云', age=30}]
}
}