List集合
我们主要介绍java.util.List
集合和java.util.Set
集合
List接口介绍
java.util.List
接口继承自Collection接口,是单列集合的一个重要分支,在List集合当中允许出现重复的元素,所有的元素都是以一种线性方式进行存储的,在List集合当中基本上我们可以通过索引来访问集合当中的元素。另外List集合还有一个特点就是元素是有序的,指的是存取元素顺序相同。
List接口当中的常用API方法:增删改查
出了继承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) :在指定索引位置上替换成给定的元素,并且返回更新前的元素。
List集合的子类
ArrayList集合
有索引,有序,元素可重复,长度可变的数组,可以存储null元素,元素增删慢,查询快.
详情请点击
LinkedList集合
java.util.LinkedList
集合存储的结构底层是一个链表结构,是一个双向链表结构,方便元素的添加和删除
我们在开发中对一个链表集合中的元素大量的都是采用首尾节点操作(添加和删除):常用的API方法如下:
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
LinkedList集合的特点:
1.底层是一个链表结构:查询慢,增删快
2.里面包含了大量的首尾节点操作的方法
3.允许所有元素(包括null)
4.此实现不是同步的,如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须保持外部同步
LinkedList 是 List的子类,List当中的方法LinkedList都能使用 在开发中,LinkedList集合也可以作为堆栈、队列结构使用
Set接口
java.util.Set
接口和 java.util.list
接口是一样的,都是继承于Collection接口,它与Collection接口当中的方法基本一样,没有对Collection进行功能上的扩展,只是比Collection接口更加严格。与List接口不同的是,Set接口中的元素是无序的,并且都会以某种规则保证存入的元素不重复。
Set接口有很多个子类,我们主要介绍两个重要子类:java.util.HashSet 和 java.util.LinkedHashSet 集合
Set集合取出元素的方式可以采用:迭代器、增强for循环
java.util.Set extends Collection接口
Set接口的特点:
1. 不允许存储重复性的元素
2. 没有索引,没有带索引的方法,也不能使用普通的for循环进行遍历
java.util.HashSet implements Set 接口
HashSet集合的特点:
1. 不允许存储重复性的元素
2. 没有索引,没有带索引的方法,也不能使用普通的for循环进行遍历
3. 是一个无序的集合,存储的元素顺序和取出元素的顺序可能不一样
4. 底层是一个哈希表结构(查询的速度非常快)
HashSet集合介绍
java.util.HashSet
是Set接口的一个实现类,它存储的元素是不可重复的,并且元素都是无序的(存取顺序不一致)。java.util.HashSet
底层的实现其实是一个java.util.HashMap
支持的。
HashSet
是根据对象的哈希值来确定元素在集合当中的存储位置,因此它具有良好的存取和查找性能。保证元素唯一性的方式依赖于hashCode
和equals
方法
哈希值: 是一个十进制的整数,由系统随机给出(就是对象的地址值:是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
是由Object类中有一个方法:可以获取到对象的哈希值
int hashCode() 返回该对象的哈希码值
HashSet集合存储数据的结构(哈希表)
什么是哈希表呢?
在JDK1.8之前,哈希表的底层采用的是数组 + 链表实现,即使用链表处理哈希冲突,同一哈希值的链表都存储在一个链表里,但是当位于一个链中的元素较多时,即hash值相等的元素较多时,通过key值依次查找的效率很低下。在JDK1.8中,哈希表存储结构采用数组 + 链表/红黑树实现的,当链表的长度超过阈值 (8)时,将链表转换成红黑树结构,这样的好处是大大减少了查找的时间
总而言之,JDK1.8之后引入红黑树结构大大优化了HashMap的性能,那么对于我们来讲保证HashSet元素唯一不重复,其实是根据对象的hashCode和equals方法来决定的。如果我们往集合当中存储的是自定义的对象,需要保证对象的唯一性,就必须重写HashCode和equals方法,来自定义当前对象的比较方式
HashSet存储自定义类型的元素
一般需要重写对象当中的hashCode和equals方法,建立自己的比较方式。才能保证HashSet集合中元素的唯一性
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
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
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
**@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 &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}**
}
LinkedHashSet集合
我们知道HashSet保证元素的唯一,可是存进去的元素是没有顺序的,那么如何保证存进去的元素是有序的?
在java.util.HahSet
类的下面还有一个子类java.util.LinkedHashSet
,它是链表和哈希表的组合的一个数据存储结构。
java.util.LinkedHashSet集合 extends java.util.HashSet集合
LinkedHashSet集合:
底层是一个哈希表(数组+链表/红黑树) + 链表:多了一条链表(记录元素的存储的顺序),从而来保证元素的有序。
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,
后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,
即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。
代码示例:
// 构建一个LinkedHashSet集合对象
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("www");
linkedHashSet.add("zhiyou100");
linkedHashSet.add("com");
linkedHashSet.add("abc");
linkedHashSet.add("abc");
linkedHashSet.add("java");
linkedHashSet.add("python");
// [www, zhiyou100, com, abc, java, python]
System.out.println(linkedHashSet);// [www, zhiyou100, com, abc] 有序的,不重复的
可变参数
在JDK1.5之后,如果我们定义一个方法需要接收多个参数,并且多个参数的数据类型一致,那么我们可以简化成如下格式:
修饰符 返回值类型 方法名(参数类型...形参名){
//...
}
其实上面的格式完全等价于:
修饰符 返回值类型 方法名(参数类型[] 参数名){
//...
}
只是后面的写法,在方法调用时,必须传递一个数组类型,而前者可以直接传递参数数据。
JDK1.5之后,出现的这种简化操作。 "…"用在参数上,我们称之为可变参数。
同样是代表数字,但是在方法调用这个带有可变参数时,不用创建数组,而是直接将数组当中的元素作为实际参数进行传递,其实编译生成的class文件,本质是将这些元素封装到了一个数组当中,再进行数据传递,这些动作都在编译生成.class文件的时候,自动完成了。
可变参数的注意事项:
1.一个方法的参数列表,只能有一个可变参数
2.如果方法的参数有多个,类型不止一种,那么可变参数必须写在参数列表的末尾位置
代码示例:
public static void add(int... arr) {
//System.out.println(arr);// [I@1b6d3586 底层就是一个数组
//System.out.println(arr.length);//0
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println(sum); // 30
}
Collection集合工具类
常用功能
java.util.Collections 是集合工具类,用来操作集合对象中的元素 方法如下:
public static <T> boolean addAll(Collection<? super T> c,T...elements):
往集合中一次性添加多个元素。
public static <T> void shuffle(List(?) list):
打乱集合中的元素顺序。
public static <T> void sort(List<T> list):
将集合中的元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<? super T>c)
: 将集合中的元素按照指定的规则进行排序。
import java.util.ArrayList;
import java.util.Collections;
/*
public static <T> boolean addAll(Collection<? super T> c,T...elements):往集合中一次性添加多个元素。
public static <T> void shuffle(List(?) list):打乱集合中的元素顺序
*/
public class Demo01Collections {
public static void main(String[] args) {
ArrayList<String> strs = new ArrayList<>();
/*strs.add("abc");
strs.add("小赵");
strs.add("小孙");
strs.add("小刘");*/
// 使用Collections集合工具类的addAll()
Collections.addAll(strs,"abc","小孙","小刘","小赵","123","a");
System.out.println(strs);
Collections.shuffle(strs);
System.out.println(strs);
}
}
import java.util.ArrayList;
import java.util.Collections;
public class Demo02Collections {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(123);
list01.add(127);
list01.add(125);
list01.add(126);
list01.add(121);
list01.add(124);
System.out.println(list01);
// 排序
Collections.sort(list01);
System.out.println(list01);
ArrayList<String> list02 = new ArrayList<>();
// 增加元素
Collections.addAll(list02,"a","c","ab","c","d","ac","abc","ba");
// 排序 个人认为是按照首字母排序
Collections.sort(list02);
System.out.println(list02);
System.out.println("------------------------");
// 添加学生
ArrayList<Student> list03 = new ArrayList<>();
list03.add(new Student("小孙",20));
list03.add(new Student("小王",21));
list03.add(new Student("小周",18));
list03.add(new Student("小赵",15));
System.out.println(list03);
// 对学生按照一定规则进行排序 排序规则在学生类中
Collections.sort(list03);
System.out.println(list03);
}
}
学生类
public class Student implements Comparable<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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// 重写排序规则
@Override
public int compareTo(Student o) {
// return 0:代表的是两个元素相同
// 自定义排序规则:按照年龄进行排序
// this参数,o参数
// this.getAge() - o.getAge() // 升序排序
// o.getAge() - this.getAge() // 降序排序
return this.getAge() - o.getAge();
}
}