1.List接口
java.util.List
接口extendsCollection
接口
List接口的特点:
1.有序的集合,存储元素和取出元素的顺序是一致的(存储123,取出123)
2.有索引,包含了一些带索引的方法
3.允许存储重复的元素
List接口中带有索引的方法(特有):
1.public void add (int index,E element):将指定的元素,添加到该集合中的指定位置上。
2.public E get (int index):返回集合中指定位置的元素。
3.public E remove (int index):移除列表中指定位置的元素,返回的是被移除的元素。
4.public E set (int index,E element):用指定元素替换集合中指定位置的元素,返回该值的更新前的元素。
注意:操作的时候一定要防止索引越界异常
代码实例:
import java.util.ArrayList;
import java.util.List;
public class List01 {
public static void main(String[] args) {
List<Integer>l1=new ArrayList<>();
//add往集合中添加元素
l1.add(12);
l1.add(23);
l1.add(34);
System.out.println(l1);//[12, 23, 34]
//在指定位置上添加元素
l1.add(2,0);//在2号索引位置上添加元素 0
System.out.println(l1);//[12, 23, 0, 34]
//get 返回集合中指定位置的元素
System.out.println(l1.get(2));//0
//remove移除指定位置的元素,返回被移除的元素
Integer re = l1.remove(3);
System.out.println(re);//34
//用指定元素替换集合中指定位置的元素
Integer s = l1.set(2, 30);
System.out.println(s);//0
System.out.println(l1);//[12, 23, 30]
}
}
1.1 ArrayList集合
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
但是开发时非常随意地使用ArrayList完成任何需求,并不严谨,不提倡。
1.2 LinkedList集合
java.util.LinkedList
集合数据存储的结构是链表结构。方便元素添加、删除的集合。
LinkedList是一个双向链表
LinkedList集合的特点:
1.底层是一个链表结构:查询慢增删快
2.其中包含大量操作首尾元素的方法
注意:使用LinkedList集合特有的方法,不能使用多态
方法:
1.public void addFirst(E e):将指定元素插入此列表的开头。
2.public void addLast(E e):将指定元素添加到此列表的结尾。
3.public void push(E e):将元素推入此列表所表示的堆栈。此方法等效于addFirst方法
4.public E pop():从此列表所表示的堆栈处弹出一个元素。
5.public E getFirst():返回此列表的第一个元素。
6.public E getLast():返回此列表的最后一个元素。
7.public E removeFirst():移除并返回此列表的第一个元素。
8.public E removeLast():移除并返回此列表的最后一个元素。
9.public boolean isEmpty():如果列表不包含元素,则返回true。
代码示例:
import java.util.LinkedList;
public class LinkedList01 {
public static void main(String[] args) {
LinkedList<Integer>list=new LinkedList<>();
list.add(0);
list.add(9);
list.add(12);
list.add(23);
list.add(30);
System.out.println(list);//[0, 9, 12, 23, 30]
//将指定元素插入此列表的开头。
list.addFirst(2);
System.out.println(list);//[2, 0, 9, 12, 23, 30]
//将指定元素添加到此列表的结尾
list.addLast(24);
System.out.println(list);//[2, 0, 9, 12, 23, 30, 24]
//将元素推入此列表所表示的堆栈
list.push(45);
System.out.println(list);//[45, 2, 0, 9, 12, 23, 30, 24]
//从此列表所表示的堆栈处弹出一个元素
Integer p = list.pop();
System.out.println(p);//45
System.out.println(list);//[2, 0, 9, 12, 23, 30, 24]
//返回此列表的第一个元素
System.out.println(list.getFirst());//2
//返回此列表的第一个元素
System.out.println(list.getLast());//24
//移除并返回此列表的第一个元素
Integer first = list.removeFirst();
System.out.println(first);//2
System.out.println(list);//[0, 9, 12, 23, 30, 24]
//移除并返回此列表的最后一个元素
System.out.println(list.removeLast());//24
System.out.println(list);//[0, 9, 12, 23, 30]
//增强for遍历
for (Integer in : list) {
System.out.println(in);
}
//判断集合是否为空
System.out.println(list.isEmpty());//false
//清空集合中的元素
list.clear();
System.out.println(list);//[]
System.out.println(list.isEmpty());//true
}
}
2.Set接口
java.util.Set
接口和java.util.List
接口一样,同样继承自Collection
接口,它与Collection
接口中的方法基本一致,并没有对Collection
接口进行功能上的扩充,只是比Collection
接口更加严格了。与List
接口不同的是,Set
接口中元素无序,并且都会以某种规则保证存入的元素不出现重复。
Set
集合有多个子类,包括java.util.HashSet
、java.util.LinkedHashSet
等集合。
tips:Set集合取出元素的方式可以采用:迭代器、增强for。
Set接口的特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
2.1HashSet
java.util.HashSet
集合 implements Set
接口
HashSet特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4.底层是一个哈希表结构(查询的速度非常快)
代码如下:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashSet01 {
public static void main(String[] args) {
Set<Integer>set=new HashSet<>();
set.add(12);
set.add(23);
set.add(34);
set.add(12);
//增强for遍历
for (Integer in : set) {
System.out.println(in);//34 23 12(不允许添加重复的元素)
}
//或者迭代器遍历
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
哈希值:是一个十进制的整数,由系统随机给出(就是一个地址,是模拟得到的地址,不是数据实际存储的物理地址)
在Object
类中有一个方法可以获取哈希值
int hashCode();
返回该对象的哈希码值。
public class HashCodeMain {
public static void main(String[] args) {
Person p1=new Person();
int h1 = p1.hashCode();
System.out.println(h1);//1854778591
Person p2=new Person();
int h2 = p2.hashCode();
System.out.println(h2);//2054798982
System.out.println(p1);//me.rusell.l02.Person@6e8dacdf
System.out.println(p2);//me.rusell.l02.Person@7a79be86
System.out.println(p1==p2);//false
}
}
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
JDK1.8引入红黑树大程度优化了HashMap的性能,保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCode和equals方法建立属于当前对象的比较方式。
HashSet存储自定义类型元素
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
创建自定义Person类:
import java.util.Objects;
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 String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//覆盖重写hashCode和equals方法
@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);
}
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;
}
}
创建对象:
import java.util.HashSet;
/*
HashSet存储自定义类型元素
要求:同名、同年龄的人视为同一元素,只能存储一次
*/
public class HashSetPerson {
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Person>set=new HashSet<>();
Person p1=new Person("李白",28);
Person p2=new Person("李白",26);
Person p3=new Person("李白",28);
Person p4=new Person("杜甫",26);
System.out.println(p1.hashCode());//1854778591
System.out.println(p2.hashCode());//2054798982
System.out.println(p3.hashCode());//885951223
System.out.println(p1==p3);//false(此处比较的是地址值)
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
System.out.println(set);//[Person{name='李白', age=28}, Person{name='李白', age=28}, Person{name='杜甫', age=26}, Person{name='李白', age=26}]
//在Person类中重写hashCode和equals方法之后
System.out.println(set);//[Person{name='李白', age=28}, Person{name='李白', age=26}, Person{name='杜甫', age=26}]
}
}
2.2 LinkedHashSet
在HashSet下面有一个子类java.util.LinkedHashSet
,它是链表和哈希表组合的一个数据存储结构。
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表记录元素的存储顺序,保证元素有序
代码如下:
import java.util.HashSet;
import java.util.LinkedHashSet;
public class LinkedHashSetMain {
public static void main(String[] args) {
//定义一个HashSet集合
HashSet<String> set=new HashSet<>();
set.add("Rusell");
set.add("Westbrook");
set.add("Rusell");
set.add("okc");
System.out.println(set);//[Rusell, okc, Westbrook]:不能重复存储且无序
//定义一个LinkedHashSet集合
LinkedHashSet<String> link=new LinkedHashSet<>();
link.add("老李");
link.add("老张");
link.add("老李");
link.add("老王");
System.out.println(link);//[老李, 老张, 老王]:不能重复存储但有序
}
}