单例集合的使用,容器002

本文介绍了Java集合框架中的List接口及其常见实现类ArrayList、LinkedList和Vector的特点和使用。ArrayList基于数组实现,查询高效,增删低效;Vector线程安全但效率较低;LinkedList使用双向链表,适合频繁增删操作。同时,文章还提到了Stack(Vector子类)和Set接口的HashSet与TreeSet,讨论了它们的实现原理和排序规则。
摘要由CSDN通过智能技术生成

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 TypeMethod 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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值