JavaDay06——集合进阶

本文详细介绍了Java集合框架中的ArrayList、Set(HashSet, LinkedHashSet, TreeSet)、Map(HashMap, LinkedHashSet, TreeSet)的使用方法,包括添加、删除、查找、排序及并发修改注意事项。特别关注哈希值、Set的无重复性与List的有序性,以及如何处理并发修改异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、集合回顾
ArrayList 类
void add​(int index, E element) 在此列表中的指定位置插入指定元素
boolean add​(E e) 将指定的元素附加到此列表的末尾。
E get​(int index) 返回此列表中指定位置的元素。
E remove​(int index) 移除此列表中指定位置的元素。
boolean remove​(Object o) 从此列表中删除第一次出现的指定元素(如果存在)。
E set​(int index, E element) 用指定的元素替换此列表中指定位置的元素。
int size() 返回此列表中的元素数。
2、集合进阶
2.1、Collection是单例集合的顶层接口,它表示一组对象,这些对象被称为Collection元素,JDK不提供此接口的任何直接实现,它提供更加具体的子接口Set和List实现。创建Collection集合的对象采用多态的方式、具体实现类ArrayList。
2.2、Collection集合常用的方法:
boolean add​(E e) 确保此集合包含指定的元素(可选操作)。
void clear() 从此集合中删除所有元素(可选操作)。
boolean contains​(Object o) 返回true此集合是否包含指定的元素。
boolean isEmpty() true如果此集合不包含元素,则返回。
int size() 返回此集合中的元素数。
Iterator iterator() 返回此集合中元素的迭代器。
iterator常用的方法:
E next() 返回迭代中的下一个元素。
boolean hasNext() true如果迭代有更多元素,则返回。

public static void main(String[] args) {
        Collection<String> ct = new ArrayList<String>();
        ct.add("hello");
        ct.add("java");
        ct.add("javase");
        ct.add("javaee");
        System.out.println(ct.contains("hello"));//判断集合中是否有这个元素
        //Iterator<E>	iterator()	返回此集合中元素的迭代器。
        Iterator<String> it = ct.iterator();//Iterator<E>	iterator()	返回此集合中元素的迭代器。
        while (it.hasNext()){//boolean	hasNext()	true如果迭代有更多元素,则返回
            String s = it.next();//E	next()	返回迭代中的下一个元素。
            System.out.println(s);
        }
    }

2.3 List集合
什么是List集合?
是有序集合(也被称为序列) 用户可以精确控制每个元素在列表中的插入位置。用户可以通过它们的整数索引(在列表中的位置)访问元素,并在列表中搜索元素。与set集合不同,列表通常允许重复元素。
List集合特点:可重复,有序
List集合特有的方法:
void add​(int index, E element) 在此列表中的指定位置插入指定元素(可选操作)。
E set​(int index, E element) 用指定的元素替换此列表中指定位置的元素(可选操作)。
E remove​(int index) 移除此列表中指定位置的元素(可选操作)。返回被删除元素

public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        //void	add​(int index, E element)	在此列表中的指定位置插入指定元素(可选操作)。
        list.add("Java");
        list.add("JavaEE");
        list.add("JavaSE");
        //E	set​(int index, E element)	用指定的元素替换此列表中指定位置的元素(可选操作)。
        list.set(1,"I");
        //E	remove​(int index)	移除此列表中指定位置的元素(可选操作)。返回被删除元素
        list.remove(0);
        //迭代器遍历
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String s=it.next();
            System.out.println(s);
        }
    }

并发修改异常:ConcurrentModificationException
出现原因:当不允许此类修改时,检测到对象的并发修改的方法可能会抛出此异常。在使用next方法时会检测集合实际修改次数和预期修改次数ArrayList.this.modCount != this.expectedModCount。调用add方法时会使得modCount++导致两者不相等抛出ConcurrentModificationException异常。

while (it.hasNext()){
            String s=it.next();
            if(s.equals("Java")){
                list.add("java");
            }
        }

修改方法:遍历方式改为for循环,使用get方法获取集合元素。

for (int i=0;i<list.size();i++){
            String s = list.get(i);
            if(s.equals("Java")){
                list.add("java");
            }
        }

列表迭代器:List.listIterator()创建一个列表迭代器。
void add​(E e)将指定的元素插入列表(可选操作)。不会发生并发异常

while (lit.hasNext()){
            String s=lit.next();
            if(s.equals("Java")){
                lit.add("java");//void	add​(E e)将指定的元素插入列表(可选操作)。不会发生并发异常
            }
        }
        System.out.println(list);

增强for循环
目的:简化数组和Collection集合的遍历
增强的格式
for(元素数据类型 变量名:数组或Collection集合){
元素就是变量名

LinkedList集合:
LinkedList同时实现了List接口和Deque接口,也就是收它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(stack)
LinkedList特有的方法:
void addFirst​(E e) 在此列表的开头插入指定的元素。
void addLast​(E e) 将指定的元素附加到此列表的末尾。
E getFirst() 返回此列表中的第一个元素。
E getLast() 返回此列表中的最后一个元素。
E removeFirst() 移除并返回此列表中的第一个元素。
E removeLast() 从此列表中删除并返回最后一个元素。

public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<String>();
        list.add("hello");
        list.add("java");
        //void	addFirst​(E e)	在此列表的开头插入指定的元素。
        list.addFirst("JavaSE");
        //	void	addLast​(E e)	将指定的元素附加到此列表的末尾。
        list.addLast("JavaEE");
        //	E	getFirst()	返回此列表中的第一个元素。
        String lf = list.getFirst();
        System.out.println("列表中第一个元素是:"+lf);
        //	E	getLast()	返回此列表中的最后一个元素。
        String ll = list.getLast();
        System.out.println("列表中最后一个元素是:"+ll);
        System.out.println(list);
        System.out.println("--------");
        //	E	removeFirst()	移除并返回此列表中的第一个元素。
        String lrm = list.removeFirst();
        System.out.println("列表中被删除的第一个元素是:"+lrm);
        //	E	removeLast()	从此列表中删除并返回最后一个元素。
        String llm = list.removeLast();
        System.out.println("列表中被删除的最后一个元素是:"+llm);
        System.out.println(list);
    }

3、Set集合
3.1、Set集合的特点:不包含重复元素的集合、没有带索引的方法所以不能使用普通遍历
3.1、哈希值:是JDK根据地址或字符串或数值计算出来的int类型的数值

public static void main(String[] args) {
        //int	hashCode()
        //Returns a hash code value for the object.
        Student student = new Student();
        Student student1 = new Student();

        //默认情况下不同对象的哈希值是不同的
        //通过方法重写,可以实现不同对象的哈希值相同
        System.out.println(student.hashCode());//764977973
        System.out.println(student.hashCode());//764977973
        System.out.println(student1.hashCode());//381259350
        System.out.println("hello".hashCode());//99162322
        System.out.println("word".hashCode());//3655434
        System.out.println("天才".hashCode());//732740
        System.out.println("神仙".hashCode());//983355
    }

3.3、HashSet集合
底层数据结构是哈希表、对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的顺序一致、没有带索引的方法,所以不能使用普通for循环遍历、由于是Set集合,所以不包含重复元素的集合

public static void main(String[] args) {
        HashSet<String> hash = new HashSet<>();
        hash.add("Java");
        hash.add("wrold");
        hash.add("JavaSE");
        for (String hashSet:hash){
            System.out.println(hashSet);//不保证存储和取出的数据一致
        }
    }

HashSet练习:要求集合添加学生对象,统一名称视为同一个对象

public static void main(String[] args) {
        HashSet<Student> hash = new HashSet<>();
		Student s1 = new Student("张三", 20);
        Student s2 = new Student("李四", 20);
        Student s3 = new Student("王五", 20);
        Student s4 = new Student("王五", 20);
        hash.add(s1);
        hash.add(s2);
        hash.add(s3);
        hash.add(s4);
        for (Student hashs:hash){
            System.out.println(hashs);
        }
 }

这里我们需要在student类中重写hashCode()和equals()方法
3.4、LinkedHashSet集合
1、哈希表和链表实现Set接口具有可预测的迭代性
2、链表保证元素的有序
3、哈希表保证元素的唯一

public static void main(String[] args) {
        LinkedHashSet<String> hash = new LinkedHashSet<>();
        hash.add("Java");
        hash.add("JavaSE");
        hash.add("JavaEE");
        for (String hashs:hash){
            System.out.println(hashs);
        }
    }

3.5、TreeSet集合
1、元素不重复
2、排序根据构造方法来:无参构造函数进行自然排序,带参构造函数根据参数排序接口
3、没有索引,不能使用普通for循环遍历

 //TreeSet()
        //构造一个新的空树集,根据其元素的自然顺序排序。
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(10);
        ts.add(12);
        ts.add(13);
        ts.add(20);
        ts.add(23);
        ts.add(33);
        for (Integer i:ts){
            System.out.print(i);//101213202333
        }
        //TreeSet​(Comparator<? super E> comparator)
        //构造一个新的空树集,根据指定的比较器进行排序。
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num=s1.getAge()-s2.getAge();
                int num2= num==0?s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });
        Student s1 = new Student("zhangsan",20);
        Student s2 = new Student("lisi",30);
        Student s3 = new Student("wangwu",23);
        Student s4 = new Student("erniu",20);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        for (Student i:ts){
            System.out.println(i);
        }

练习:存储学生对象并遍历,创建TreeSet集合使用无参构造方法;要求:按照年龄大小进行排序,年龄相同则按照姓名的字母数序排序。

public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();
        Student s1 = new Student("zhangsan",20);
        Student s2 = new Student("lisi",30);
        Student s3 = new Student("wangwu",23);
        Student s4 = new Student("erniu",20);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        for (Student i:ts){
            System.out.println(i);
        }
    }

需要Student类实现Comparable 接口,重写public int compareTo(Student s)方法。方法内容为排序规则

 @Override
    public int compareTo(Student s) {
//        return 0;//只会添加一个进集合
//        return 1;//按存储顺序添加进集合
//        return -1;//按存储顺序倒序添加进集合
        int num=this.age-s.age;//按照年龄大小升序排列
//        int num=s.age-this.age;//按照年龄大小降序排列
        int num2= num==0?this.name.compareTo(s.name):num;
        return num2;
    }

练习:

public static void main(String[] args) {
        /*
        * 练习:创建一个set集合
        * 创建一个随机数
        * 随机数在0-20
        * 存入set集合
        * 遍历,随机数不重复
        * */
//        HashSet<Integer> s = new HashSet<>();
        TreeSet<Integer> s = new TreeSet<>();
        Random r = new Random();
        while (s.size()<10){
            int number = r.nextInt(20)+1;
            s.add(number);
        }
        for (Integer i:s){
            System.out.println(i);
        }
    }

4、泛型
泛型定义:泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型。它的本质是参数化类型
泛型好处:把运行时期的问题提前到了编译期间、避免了强制类型转换
泛型类:
泛型类的定义格式:
修饰符 class 类名<类型>{}
泛型方法:
泛型方法的定义格式:
修饰符<类型>返回值类型方法名(类型 变量名){}
泛型接口:
泛型接口的定义格式:
修饰符 interface 接口名<类型>{}

public class test10 {
    public static void main(String[] args) {
        /*
        * 泛型类测试
        * */
//        A<String> a1 = new A<>();
//        a1.setT("张三");
//        System.out.println(a1.getT());
//        A<Integer> a2 = new A<>();
//        a2.setT(123);
//        System.out.println(a2.getT());


        /*
        * 泛型方法测试
        * */
//        B b = new B();
//        b.show(123);
//        b.show("zsls");
//        b.show(true);


        /*
        * 泛型接口测试
        * */
//        A<String> s1 = new A<>();
//        s1.show("张三");
//        A<Integer> s2 = new A<>();
//        s2.show(123);
    }
}
class A<T> implements c<T>{
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
class B{

    public <T> void show(T t){
        System.out.println(t);
    }
}
interface c<T>{
    void show(T t);
}

类型通配符:<?>可以任何一种类型;<?extends 类型> 类型上限;<? super 类型>类型下限
可变参数
格式: 修饰符 返回值类型 方法名(类型…变量名){}
注意事项:可变参数应当放在后面例如 public static int sum(int b,int…a){},可变参数其实是一个数组

可变参数的使用:Arrays类、List接口、Set接口

 public static void main(String[] args) {
        //Arrays中有一个静态的方法    static <T> List<T>	asList​(T... a)返回由指定数组支持的固定大小列表。
//        List<String> list = Arrays.asList("hello","java");
//        list.add("javaSE");//UnsupportedOperationException

        //List接口中有一个静态的方法   static <E> List<E>	of​(E... elements)返回包含任意数量元素的不可修改列表。
//        List<String> list = List.of("1", "Java", "world");
//        list.add("javaSE");//UnsupportedOperationException
        //Set接口中有一个静态的方法    static <E> Set<E>	of​(E... elements)返回包含任意数量元素的不可修改集合。
//        Set<String> list = Set.of("1", "Java", "world");
//        list.add("javaSE");//UnsupportedOperationException
//        System.out.println(list);
    }

5 、Map集合
Map集合类似与Python的字典,存储的是键值对对象。Map不能包含重复的键;每个键最多可以映射到一个值。
Map基本功能如代码所示:

public static void main(String[] args) {
        /*
        * Map集合的基本功能
        * */
        Map<String, String> map = new HashMap<>();
        //V	put​(K key, V value)  将指定值与此映射中的指定键相关联(可选操作)。
        map.put("1802076","软件工程6班");
        map.put("1802075","软件工程5班");
        map.put("1802074","软件工程4班");
        map.put("1802073","软件工程3班");
//        System.out.println(map);
        //V	remove​(Object key) 如果存在,则从此映射中删除键的映射(可选操作)。返回值为值
//        System.out.println(map.remove("1802076"));
        //int	size()返回此映射中键值映射的数量。
//        System.out.println(map.size());
        //boolean	containsKey​(Object key)返回true此映射是否包含指定键的映射。
        //boolean	containsValue​(Object value)返回true此映射是否将一个或多个键映射到指定值。
//        System.out.println(map.containsKey("1802076"));//true
//        System.out.println(map.containsKey("1802071"));//false
        //void	clear()从此映射中删除所有映射(可选操作)。
//        map.clear();
        //boolean	isEmpty()返回true如果此映射不包含键-值映射关系。
//        System.out.println(map.isEmpty());//false
        /*
        *Map的获取功能
        * */
        //V	get​(Object key)返回指定键映射到的值,或者null如果此映射不包含键的映射。
//        System.out.println(map.get("1802076"));
//        System.out.println(map.get("1802071"));
        //Set<K>	keySet() 返回Set此映射中包含的键的视图。
//        System.out.println(map.keySet());
        //Collection<V>	values()返回Collection此映射中包含的值的视图。
//        System.out.println(map.values());
        /*
        * Map集合的遍历方式1
        * 1、通过键获取值
        * 2、通过增强for循环来遍历
        * */
        Set<String> keySets = map.keySet();
        for (String key:keySets){
            System.out.println(key+"="+map.get(key));
        }
        /*
        * Map集合的遍历方式2
        * 1、直接获取键值对对象
        * 2、通过增强for循环遍历
        * */
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String,String> entry:entries){
            System.out.println(entry);
        }

练习:
键存储student类,值为String类,如果键里面对象内容一样则判断是同一个键,将值修改为最新的值
需要在student类中重写hasCode()和equals()方法。

HashMap<Student, String> hm = new HashMap<>();
        Student s1 = new Student("刘备", 30,"蜀国");
        Student s2 = new Student("黄盖", 40,"东吴");
        Student s3 = new Student("周瑜", 27,"东吴");
        Student s4 = new Student("小乔", 24,"东吴");
        Student s5 = new Student("小乔", 24,"东吴");
        hm.put(s1,"蜀国");
        hm.put(s2,"东吴");
        hm.put(s3,"东吴");
        hm.put(s4,"东吴");
        hm.put(s5,"大汉");
        Set<Map.Entry<Student, String>> entries = hm.entrySet();
        for (Map.Entry<Student, String> entry:entries){
            String value = entry.getValue();
            System.out.println(entry.getKey().name+"来自"+value);
        }
/*
         * 练习:
         * 统计字符串中每个字符出现的次数
         * 需求:键盘录入一串字符,要求统计字符串中字符出现的次数
         * 例:aaabbbbccc 输出a(3)b(4)c(3)
         * */
        Scanner scanner = new Scanner(System.in);
        HashMap<Character, Integer> hm = new HashMap<>();
        String line = scanner.nextLine();
        for (int i = 0; i < line.length(); i++) {
            char key = line.charAt(i);
            Integer value = 1;
            if (hm.get(key) == null) {
                hm.put(key, value);
            } else {
                value=hm.get(key)+1;
                hm.put(key, value);
            }
        }
        Set<Character> keySet = hm.keySet();
        for (Character keyset:keySet){
            System.out.println(keyset+"("+hm.get(keyset)+")");
        }

6、Collections
是针对集合的操作类
有以下几种常用的方法

public static void main(String[] args) {
//        List list = new ArrayList();
//        list.add(10);
//        list.add(30);
//        list.add(40);
//        list.add(50);
//        list.add(60);
//        list.add(40);
        //static void	shuffle​(List<?> list)
        //使用默认的随机源随机排列指定的列表。
//        Collections.shuffle(list);
        //static <T extends Comparable<? super T>>
        //void	sort​(List<T> list)
        //根据其元素的自然顺序,将指定列表按升序 排序。
//        Collections.sort(list);
        //static void	reverse​(List<?> list)
        //反转指定列表中元素的顺序。
//        Collections.reverse(list);
//        System.out.println(list);
  • 练习:
    * 使用ArrayList存储学生对象,使用Collections对ArrayList排序
    * 要求:年龄从小到大排序,年龄相同,按照姓名字母排序
/*
        * 练习:
        * 使用ArrayList存储学生对象,使用Collections对ArrayList排序
        * 要求:年龄从小到大排序,年龄相同,按照姓名字母排序
        * */
        Student s1 = new Student("zhangsan", 20);
        Student s2 = new Student("zhangsan", 30);
        Student s4 = new Student("zhangsan", 230);
        Student s3 = new Student("lisi", 20);
        ArrayList<Student> list = new ArrayList<>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s4);
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num=s1.age-s2.age;
                int num2=s1.getName().compareTo(s2.getName());
                return num2;
            }
        });
        for (Student s:list){
            System.out.println(s.getName()+":"+s.age);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值