目录
List接口
java.util.List 接口继承自Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了List 接口的对象称为List集合。
在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。
另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
List集合特点(有序,可重复)
有序的集合,存储元素和取出元素的顺序是一致的(存储1,2,3 取出还是1,2,3)
它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)
集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
线程不安全,所以效率高
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) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
注意
操作索引的时候,一定要防止索引越界异常。
常见的越界异常
IndexOutOfBoundsException:索引越界异常,集合会报
ArrayIndexOutOfBoundsException:数组索引越界异常
StringIndexOutOfBoundsException:字符串索引越界异常
ArrayList集合
java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList 是最常用的集合。
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("a");
System.out.println(list);//[a, b, c, d, a] 不是地址重写了toString
Vector集合
Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:
- Vector 是同步访问的。
- Vector 包含了许多传统的方法,这些方法不属于集合框架。
Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
Vector线程安全,相对ArrayList来讲效率低。
参考:https://www.runoob.com/java/java-vector-class.html
LinkedList集合
java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合。查询慢,增删快。
LinkedList是一个双向链表:
cpublic 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<String> linked = new LinkedList<>();
//使用add方法往集合中添加元素
linked.add("a");
linked.add("b");
linked.add("c");
System.out.println(linked);//[a, b, c]
//String first = linked.removeFirst();
String first = linked.pop();
System.out.println("被移除的第一个元素:"+first);
String last = linked.removeLast();
System.out.println("被移除的最后一个元素:"+last);
System.out.println(linked);//[b]
Set接口
java.util.Set 接口和java.util.List 接口一样,同样继承自Collection 接口,它与Collection 接口中的方法基本一致,并没有对Collection 接口进行功能上的扩充,只是比Collection 接口更加严格了。与List 接口不同的是, Set 接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
特点
无序,不可重复
HashSet集合
java.util.HashSet 是Set 接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet 底层的实现其实是一个java.util.HashMap 支持。
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。
保证元素唯一性的方式依赖于: hashCode 与equals 方法。
哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值, int hashCode() 返回该对象的哈希码值。
哈希表
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。如图:
数组table 用来存储对象的哈希值,相同哈希值的元素会通过链表的方式存储。
JDK1.8引入红黑树大程度优化了HashMap的性能,对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。
HashSet存储自定义类型元素
给HashSet中存放自定义类型元素时,必须重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一。
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public 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);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"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;
}
}
要求:同名同年龄的人,视为同一个人,只能存储一次,于是用HashSet的元素不可重复性,来实现,重写Person的hashCode()和equals()方法。相同姓名和年龄的让系统判别为同一个人。
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("小美女",18);
Person p2 = new Person("小美女",18);
Person p3 = new Person("小美女",19);
System.out.println(p1.hashCode());//1967205423
System.out.println(p2.hashCode());//42121758
System.out.println(p1==p2);//false
System.out.println(p1.equals(p2));//false
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);//[Person{name='小美女', age=19}, Person{name='小美女', age=18}]
}
LinkedHashSet
在HashSet下面有一个子类java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构。
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("www");
set.add("abc");
set.add("abc");
set.add("bbb");
System.out.println(set);//[abc, www, bbb] 无序,不允许重复
LinkedHashSet<String> linked = new LinkedHashSet<>();
linked.add("www");
linked.add("abc");
linked.add("abc");
linked.add("bbb");
System.out.println(linked);//[www, abc, bbb] 有序,不允许重复
}
感谢关注