1.Collection接口中的抽象方法
方法 | 说明 |
boolean add(Object element) | 增加元素到容器中 |
boolean remove(Object element) | 从容器中移除元素 |
boolean contains(Object element) | 容器中是否包含该元素 |
int size() | 容器中元素的数量 |
boolean isEmpty() | 容器是否为空(是的话返回true) |
void clear() | 清空容器中所有的元素 |
Iterator iterator() | 获得迭代器,用于遍历所有元素 |
boolean containsAll(Collection c) | 本容器是否包含c容器中的所有元素 |
boolean addAll(Collection c) | 将容器c中所有元素增加到本容器 |
boolean removeAll(Collection c) | 移除本容器和容器c中都包含的元素 |
boolean retainAll(Collection c) | 取本容器和容器c中都包含的元素,移除非交集元素 |
Object[] to Array() | 转化成Object数组 |
List接口和Set接口都是Collection的子接口,意味着它们的实现类都有上面的方法。
2.List接口
其特点:有序(元素存入集合的顺序和取出的顺序一致,其中每个元素都有索引标记,可以根据索引来访问相关元素)。
可重复(List允许加入重复的元素。更确切的讲,List通常允许满足e1.equals(e2)的元素重复加入容器)。
List的常用抽象方法(除了继承父接口的方法,还多了些跟顺序(索引)有关的方法)
方法 | 说明 |
void add(int index,Object element) | 在指定位置插入元素,以前元素全部后移一位 |
Object set(int index,Object element) | 修改指定位置的元素 |
Object get(int indext) | 返回指定位置的元素 |
Object remove(int index) | 删除指定位置的元素,后面的元素全部前移一位 |
int indexOf(Object o) | 返回第一个匹配元素的索引,如果没有该元素,则返回-1 |
int lastIndexOf(Object o) | 返回最后一个匹配元素的索引,如果没有该元素,返回-1 |
List接口常用实现类有:ArrayList类、LinkedList类、Vector类
2.1 ArrayList容器类
ArrayList是List接口的实现类。是List存储特征的具体实现。
ArrayList底层是用数组实现的存储。特点:查询效率高,增删效率低,线程不安全。
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest {
public static void main(String[] args) {
//实例化ArrayList容器
List<String> list=new ArrayList<>();
//添加元素add()
boolean flag=list.add("xhp");
boolean flag1=list.add("111"); //List接口的父类Collection接口中的方法
System.out.println(flag);
System.out.println(flag1);
list.add(2,"222");
//索引的数值不能大于元素的个数
// list.add(4,"333"); //报错,IndexOutOfBoundsException
//获取元素get()
System.out.println(list.get(2)); //通过指定索引位置来获取列表当中的相关元素
for(int i=0;i<list.size();i++){ //循环获取list中的字符串,size()方法返回列表当中的个数。
System.out.println(list.get(i));
}
for(String l:list){ //用增强for循环获取list中的字符串
System.out.println(l);
}
//删除元素remove()
String s=list.remove(1); //通过索引来删除列表中指定位置的字符串,并返回删除的字符串
System.out.println(s);
boolean f2=list.remove("222"); //通过指定元素来删除列表中的元素,成功返回true,当给定元素在列表中不存在时才会返回false
System.out.println(f2);
//替换元素set(int index,E element)
String val=list.set(0,"xhpp66"); //通过指定索引和新替换的元素来替换原来的元素,返回被替换的元素
System.out.println(val);
//清空容器void clear()
list.clear();
System.out.println(list.size()); //输出0
boolean f3=list.isEmpty(); //判断容器是否为空,如果为空则返回true
System.out.println(f3); //输出true
//判断容器中是否包含指定元素,是则返回true,否则返回false
boolean f4=list.contains("xhp");
System.out.println(f4);
list.add("xhp");
list.add("111");
list.add("222");
list.add("xhp");
list.add("xhp");
//查找元素第一次出现的位置,返回第一次出现的索引值
int i=list.indexOf("xhp"); //如果元素在容器中不存在,则返回-1
System.out.println(i); //输出0
//查找元素最后一次出现的位置,不管中间有多少个相同元素,只返回元素最后一次出现的索引值
int i2=list.lastIndexOf("xhp"); //如果元素在容器中不存在,则返回-1
System.out.println(i2); //输出4
//将单例集合转换为数组:Object[] toArray()
Object[] array=list.toArray(); //注意不能强制把一整个数组一起转换成其他类型,只能单个单个转换!
for(Object o:array){
System.out.println(o);
}
//将单例集合转换成泛型类型数组:<T> T[] toArray(T[] a)
String[] arr2=list.toArray(new String[list.size()]);
for(String s2:arr2){
System.out.println(s2);
}
//容器的并集操作boolean addAll(Collection c),注意两个集合相并,任意一个集合都不能为空,否则返回false
ArrayList<String> a=new ArrayList<>();
ArrayList<String> b=new ArrayList<>();
ArrayList<String> c=new ArrayList<>();
a.add("a");
a.add("b");
a.add("c");
b.add("b");
b.add("c");
b.add("d");
boolean f5=a.addAll(b); //a并b,元素都在a里
boolean f6=b.addAll(c); //c集合是空的,所以应该返回false
System.out.println(f5);
System.out.println(f6);
for(String str:a){
System.out.println(str);
}
//容器的交集操作boolean retainAll(Collection c),保留两个集合相同的元素,去除不同的元素
ArrayList<String> a1=new ArrayList<>();
ArrayList<String> b1=new ArrayList<>();
a1.add("a");
a1.add("b");
a1.add("c");
b1.add("b");
b1.add("c");
b1.add("d");
boolean f7=a1.retainAll(b1); //a交b,元素都在a里
System.out.println(f7);
for(String str2:a1){
System.out.println(str2);
}
//容器的差集操作boolean removeAll(Collection c),移除本容器中包含在c容器中的数
ArrayList<String> a2=new ArrayList<>();
ArrayList<String> b2=new ArrayList<>();
a2.add("a");
a2.add("b");
a2.add("c");
b2.add("b");
b2.add("c");
b2.add("d");
boolean f8=a2.removeAll(b2);
System.out.println(f8);
for(String str2:a2){
System.out.println(str2);
}
}
}
2.2 Vector容器类
Vector也实现了List接口,与ArrayList类差不多是一样的,唯一区别就是在多线程下,Vector类较为安全。Vector底层是用数组实现的,相关的方法都加了同步检查,因此“线程安全,效率低”。eg:indexOf方法就增加了synchronized同步标记同步标记。
2.2.1 Stack容器类
Stack栈容器,是Vector的一个子类,它实现了一个标准的后进先出(LIFO:Last In Frist Out)的栈。它的特点是:后进先出,它通过5个操作方法对Vector进行扩展,允许将向量视为堆栈。
Modifier and Type | Method and Description |
boolean | empty() 如果这个栈是空的,返回true |
E | peek() 返回栈顶的元素 |
E | pop() 删除这个堆栈的顶部的元素,并返回这个元素,俗称出栈 |
E | push(E item) 把一个元素添加到堆栈的顶部,俗称进栈 |
int | search(Object o) 返回这个对象在堆栈中的位置 |
public class StackTest {
public static void main(String[] args) {
//实例化栈容器
Stack<String> stack=new Stack<>();
//将元素添加到栈容器中: E push(E item)
stack.push("a");
stack.push("b");
stack.push("c");
//返回该元素在栈中的位置: int search(Object o)
int i=stack.search("a");
System.out.println(i); //输出:3
//返回栈顶的元素: E peek()
String s=stack.peek();
System.out.println(s);
//获取栈容器中的元素,只能从栈顶开始取,直到取到栈底: E pop()
String str=stack.pop();
String str1=stack.pop();
String str2=stack.pop();
System.out.println(str+str1+str2);
//判断栈容器是否为空,如果是则返回true: boolean empty()
boolean b=stack.empty();
System.out.println(b);
}
}
Stack栈容器使用案例:匹配符号的对称性
public class StackTest {
public static void main(String[] args) {
StackTest stackTest=new StackTest();
stackTest.symmetry();
}
//匹配符号的对称性
public void symmetry(){
String str="{[()]}(){}[])";
Stack<String> stack=new Stack<>();
//假设修正法
boolean flag=true;
//拆分字符串获取字符
for(int i=0;i<str.length();i++){
char c=str.charAt(i);
if(c=='{'){
stack.push("}");
}
if(c=='['){
stack.push("]");
}
if(c=='('){
stack.push(")");
}
if(c==')'||c==']'||c=='}'){
if(stack.empty()){
flag=false;
break;
}
String x=stack.pop();
if(x.charAt(0)!=c){
flag=false;
break;
}
}
}
if(!stack.empty()){
flag=false;
}
System.out.println(flag);
}
}
2.3 LinkedList容器类
LinkedList类底层是用双向链表实现的存储,其也实现了List接口。特点:查询效率低,增删效率高,线程不安全。
双向链表也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向前一个节点和后一个节点。所以,从双向链表中的任意一个节点开始,都可以很方便地找到所有节点。
//双向链表的定义
class Node<E>{
E item;
Node<E> next;
Node<E> prev;
}
LinkedList的使用(非List接口标准),而是用于双向链表的存储结构的一些方法。
方法 | 说明 |
void addFirst(E e) | 将指定元素插入到开头 |
void addLast(E e) | 将指定元素插入到结尾 |
getFrist() | 返回此列表的第一个元素 |
getLast() | 返回此列表的最后一个元素 |
removeFirst() | 移除此列表中的第一个元素,并返回这个元素 |
removeLast() | 移除此列表中的最后一个元素,并返回这个元素 |
E pop() | 从此列表中的堆栈处弹出一个元素,等效于removeFrist() |
void push(E e) | 将元素推入此列表所表示的堆栈,等效于addFirst(E e) |
boolean isEmpty() | 判断列表是否包含元素,如果不包含元素则返回true |
import java.util.LinkedList;
//LinkedList类,其也实现了List接口,底层采用双向链表实现储存
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<>();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
for(String str:list){
System.out.print(str); //输出为:cba
}
System.out.println();
LinkedList<String> list1=new LinkedList<>();
list1.addLast("a");
list1.addLast("b");
list1.addLast("c");
for(String str:list1){
System.out.print(str); //输出为:abc
}
System.out.println();
System.out.println(list.getFirst());
System.out.println(list.getLast());
System.out.println(list.removeFirst());
System.out.println(list.removeLast());
for(String str:list){
System.out.println(str); //输出为:b
}
System.out.println("------------");
list.pop();
for(String str:list){
System.out.println(str); //输出为:abc
}
list.push("p");
list.push("h");
list.push("x");
for(String str:list){
System.out.print(str); //输出为:xhp
}
System.out.println();
System.out.println(list.isEmpty());
}
}
3. Set接口
Set接口继承Collection接口,Set接口中没有新增的方法。
Set接口特点:无序,不可重复。无序指Set中的元素没有索引,我们只能通过遍历去查找。不可重复指不允许加入重复的元素。
Set接口的常用实现类有:HashSet类、TreeSet类等,我们一般使用HashSet类。
3.1 HashSet容器类
HashSet是一个没有重复元素的集合,不保证元素的顺序,线程不安全的。而且HashSet允许有null元素。HashSet是采用哈希算法实现,底层实际是用HashMap实现的(HashSet本质就是一个简化版的HashMap),因此,查询效率和增删效率都比较高。
import java.util.HashSet;
import java.util.Set;
//HashSet类,实现了Set接口
public class HashSetTest {
public static void main(String[] args) {
//实例化HashSet
Set<String> set=new HashSet<>();
//添加元素
set.add("a");
set.add("b1");
set.add("c");
set.add("d2");
set.add("a");
//获取元素,在Set容器中没有索引,所以没有对应的get(int index)方法
for(String str:set){
System.out.println(str); //输出:a c d2 b1,充分体现了不重复性,无序性
}
//删除元素
boolean flag=set.remove("d2");
System.out.println(flag);
//返回元素个数
System.out.println(set.size());
}
}
无序:在HashSet中底层是使用HashMap存储元素的。HashMap底层使用的是数组与链表实现元素的存储,元素在数组中存放时,并不是有序存放的也不是随机存放的,而是对元素的哈希值进行运算决定元素在数组中的位置。
不重复:当两个元素的哈希值进行运算后得到相同的在数组中的位置时,会调用元素的equals()方法判断两个元素是否相同。如果元素相同则不会添加该元素,如果不相同则会使用单向链表保存该元素。
通过HashSet存储自定义对象:如果不想出现重复的数据,一定要重写equals()和hashcode()
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class Users {
private String userName;
private int userAge;
public Users() {}
public Users(String userName, int userAge) {
this.userName = userName;
this.userAge = userAge;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", userAge=" + userAge +
'}';
}
@Override
public boolean equals(Object o) {
System.out.println("equals...");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Users users = (Users) o;
return userAge == users.userAge && Objects.equals(userName, users.userName);
}
@Override
public int hashCode() {
return Objects.hash(userName, userAge);
}
}
class HashSetTest01{
public static void main(String[] args) {
Set<Users> hash=new HashSet<>();
Users u=new Users("xhp",18);
Users u1=new Users("xhp",18);
hash.add(u);
hash.add(u1);
System.out.println(u.hashCode());
System.out.println(u1.hashCode());
for(Users user:hash){
System.out.println(user);
}
}
}
3.2 TreeSet容器类
TreeSet是一个可以对元素进行排序的容器。底层实际是用TreeMap实现的,内部维持了一个简化版的TreeMap,通过key来存储Set的元素。TreeSet内部需要对存储的元素进行排序,因此,我们需要给定排序规则。
排序规则实现方式:
1.通过元素自身实现比较规则。
2.通过比较器指定比较规则。
1.通过元素自身实现比较规则
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
//TreeSet类,实现了Set接口
public class TreeSetTest {
public static void main(String[] args) {
//实例化TreeSet
Set<String> set=new TreeSet<>();
//添加元素
set.add("c");
set.add("b");
set.add("a");
set.add("d");
set.add("a");
for(String str:set){
System.out.println(str);
}
//通过元素自身实现比较规则
Set<User> tree=new TreeSet<>();
User user=new User("xhp",18);
User user1=new User("pp",16);
User user2=new User("xhp",16);
tree.add(user);
tree.add(user1);
tree.add(user2);
for(User u:tree){
System.out.println(u);
}
}
}
class User implements Comparable<User> {
private String userName;
private int userAge;
public User() {}
public User(String userName, int userAge) {
this.userName = userName;
this.userAge = userAge;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getUserAge() {
return userAge;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", userAge=" + userAge +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return userAge == user.userAge && Objects.equals(userName, user.userName);
}
@Override
public int hashCode() {
return Objects.hash(userName, userAge);
}
//定义比较类型
//正数:大,负数:小,0:相等
@Override
public int compareTo(User o) {
if(this.userAge>o.getUserAge()){
return 1;
}
if(this.userAge==o.getUserAge()){ //当年龄相同时,通过名字来排序
return this.userName.compareTo(o.getUserName());
}
return -1;
}
}
2.通过比较器实现比较规则
通过比较器定义比较规则时,我们需要单独创建一个比较器,比较器需要实现Comparator接口中的compare方法来定义比较规则。在实例化TreeSet时将比较器对象交给TreeSet来完成元素的排序处理。此时元素自身就不需要实现比较规则了。
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest01 {
public static void main(String[] args) {
Set<Student> tree=new TreeSet<>(new StudentComparator());
Student s=new Student("xhp",20);
Student s1=new Student("bb",18);
Student s2=new Student("zz",20);
tree.add(s);
tree.add(s1);
tree.add(s2);
for(Student stu:tree){
System.out.println(stu);
}
}
}
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;
}
@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);
}
}
//创建比较器
class StudentComparator implements Comparator<Student> {
//定义比较规则
@Override
public int compare(Student o1, Student o2) {
if(o1.getAge()>o2.getAge()){
return 1;
}
if(o1.getAge()==o2.getAge()){
return o1.getName().compareTo(o2.getName());
}
return -1;
}
}