2023年7月17日,比较器,TreeMap底层,LinkedHashMap,Set接口

news2024/11/28 10:43:54

比较器

Comparator是外部比较器,用于比较来对象与对象之间的,两个对象进行比较,多用于集合排序

Comparable可以认为是一个内比较器,根据对象某一属性进行排序的。

1. 使用场景

​ 内置比较器(Comparable)的使用场景:

  • 内置比较器适用于对象本身已经具有默认的排序规则,并且这个排序规则是对象的固有属性。
  • 当对象实现了 Comparable 接口并重写了 compareTo 方法后,可以直接使用内置的排序方法(如 Collections.sort)进行排序。
  • 内置比较器实现了对象的自然排序,即对象本身具有默认的排序规则。

以下是内置比较器的使用示例场景:

  1. 对象具有固有的排序属性,例如 String 类的自然排序是按照字典顺序排序。
  2. 对象的排序规则是对象自身的属性,例如 Student 类的 compareTo 方法根据学生的分数进行排序。
  3. 使用内置的排序方法进行排序时,无需额外提供比较器。

​ 外置比较器(Comparator)的使用场景:

  • 外置比较器适用于对象的排序规则是外部定义的,与对象本身的属性无关。
  • 当对象的排序规则不是对象本身的固有属性,或者需要根据不同的比较规则进行排序时,可以使用外置比较器。
  • 外置比较器可以根据需要定义多个不同的比较规则,并在需要时传递给排序方法或集合类的构造函数。

以下是外置比较器的使用示例场景:

  1. 对象的排序规则与对象本身的属性无关,例如按照对象的名称长度进行排序。
  2. 需要根据不同的比较规则进行排序,例如根据学生的分数、姓名、年龄等属性进行排序。
  3. 在排序方法或集合类的构造函数中需要传入自定义的比较器。

​ 总结:

  • 内置比较器适用于对象本身具有默认的排序规则的情况,无需额外提供比较器。
  • 外置比较器适用于对象的排序规则与对象本身的属性无关,或者需要根据不同的比较规则进行排序的情况,需要提供自定义的比较器。

1. Comparator(外部比较器)

package com.wz.collection02;

public class Student {
    private String name;
    private int age;
    private char sex;

    public Student(String name, int age, char sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public char getSex() {
        return sex;
    }

    @Override
    public String toString() {
        return name + "-" + age +"-" + sex ;
    }
}

package com.wz.collection02;

import java.util.ArrayList;
import java.util.Comparator;


public class Collection {
    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("ZhangSan",18,'男'));
        students.add(new Student("LiSi",15,'女'));
        students.add(new Student("WangWu",22,'女'));
        students.add(new Student("ZhaoLiu",28,'男'));
        students.add(new Student("SunQi",20,'女'));
//        Comparator<Student> comparator = new Comparator<Student>() {
//            @Override
//            public int compare(Student o1, Student o2) {
//                int len1 = o1.getName().length();
//                int len2 = o2.getName().length();
//                return Integer.compare(len1,len2);
//            }
//        };

        Comparator<Student> comparator = (o1, o2) -> {
            int len1 = o1.getName().length();
            int len2 = o2.getName().length();
            return Integer.compare(len1,len2);
        };
        students.sort(comparator);

        students.forEach(System.out::println);

    }
}

结果:

请添加图片描述

2. Comparable(内置比较器)

自然排序:

package com.wz.collection01;
public class Student implements Comparable<Student>{

    private final String name;

    private final double score;

    public Student(String name, double score) {
        this.name = name;
        this.score = score;
    }

    @Override
    public String toString() {
        return name + "=>" + score ;
    }

    @Override
    public int compareTo(Student other) {
        return Double.compare(score, other.score);
    }
}
package com.wz.collection01;

import java.util.*;

public class CollectionDemo {
    public static void main(String[] args) {
        Random ran = new Random();
        List<Student> students = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            Student student = new Student("stu" + i, ran.nextInt(100));
            System.out.println(student);
            students.add(student);
        }
        System.out.println("-----------------");
        //对集合进行排序,这里没有提供外排序器,因此要求集合中的元素必须实现自然排序接口
        Collections.sort(students);
        students.forEach(System.out::println);
    }
}

结果:

请添加图片描述

这段代码展示了如何使用 Comparable 接口来实现对象的自然排序。在这个示例中,Student 类实现了 Comparable<Student> 接口,并重写了 compareTo 方法来定义学生对象之间的比较规则。

CollectionDemo 类的 main 方法中,通过循环创建了 10 个学生对象,并将它们添加到 students 列表中。然后,使用 Collections.sort 方法对 students 列表进行排序。由于 Student 类实现了 Comparable 接口,因此可以直接调用 sort 方法进行排序。

compareTo 方法中,我们使用 Double.compare 方法来比较学生对象的分数。这样,排序结果将按照学生分数的升序进行排列。

最后,通过使用 forEach 方法遍历排序后的 students 列表,并使用方法引用 System.out::println 打印每个学生对象。

注意:Comparable 接口用于实现对象的自然排序,即对象本身具有默认的排序规则。如果需要根据不同的比较规则进行排序,可以使用比较器(Comparator)来实现。

TreeMap

1. TreeMap中比较器使用

TreeMap会自动对键进行排序。它是基于红黑树(Red-Black Tree)实现的,它通过对键进行自然顺序或自定义比较器的比较来保持键的有序状态。

TreeMap不是线程安全的,key不可以存入null。


TreeMap中,键是唯一的,并且按照它们的排序顺序进行存储。默认情况下,TreeMap使用键的自然顺序进行排序。例如,对于TreeMap,键按照字符串的字典顺序进行排序。

package com.wz.collection03;

import java.util.TreeMap;

public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap<String, Integer> map = new TreeMap<>();
        map.put("aa", 1);
        map.put("a", 2);
        map.put("aaa", 3);
        map.put("ba", 5);
        map.put("bc", 4);
        map.put("ab", 3);
        map.put("bb", 2);

        map.forEach((k,v) -> System.out.println(k + "=>" + v));

    }
}

结果:

请添加图片描述

TreeMap中使用外排序器

package com.wz.collection04;

import java.util.Comparator;
import java.util.TreeMap;

public class TreeMapTest {
    public static void main(String[] args) {
        Comparator<Student> comparator = (o1, o2) -> {
            int len1 = o1.getName().length();
            int len2 = o2.getName().length();
            return Integer.compare(len1,len2);
        };
        TreeMap<Student, String> map = new TreeMap<>(comparator);
        map.put(new Student("ZhangSan",18,'男'),"202312");
        map.put(new Student("LiSi",15,'女'),"202311");
        map.put(new Student("WangWu",22,'女'),"202301");
        map.put(new Student("ZhaoLiu",28,'男'),"202321");
        map.put(new Student("SunQi",20,'女'),"202305");

        map.forEach((k,v)-> System.out.println(k+"=>"+v));

    }
}

结果:

请添加图片描述

2. TreeMap底层

  1. 成员变量
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
//用于比较键的比较器。它可以是用户提供的自定义比较器,或者如果键类型实现了 Comparable 接口,则使用键类型自身的自然顺序比较器。
    private final Comparator<? super K> comparator;
//红黑树的根节点,每个节点是一个Entry
    private transient Entry<K,V> root;
//TreeMap 中键值对的数量
    private transient int size = 0;
//对 TreeMap 进行结构修改的次数
    private transient int modCount = 0;
}
    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;//节点的键
        V value;//节点的值
        Entry<K,V> left;//指向左子节点的引用。
        Entry<K,V> right;//指向右子节点的引用。
        Entry<K,V> parent;//指向父节点的引用。
        boolean color = BLACK;//表示节点的颜色,true 表示红色,false 表示黑色
        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }
//返回节点的键。
        public K getKey() {
            return key;
        }
//返回与节点键关联的值。
        public V getValue() {
            return value;
        }
//替换当前与节点键关联的值,并返回替换前的值。
        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }
//判断节点是否与给定的对象相等。
        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;

            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
        }
//返回节点的哈希码。
        public int hashCode() {
            int keyHash = (key==null ? 0 : key.hashCode());
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }

        public String toString() {
            return key + "=" + value;
        }
    }
  1. put()
  • 首先判断树是否为空树,若为空树,则直接创建根节点并返回。
  • 若树不为空,则从根节点开始,沿着树的路径,根据键的比较结果向左或向右查找插入位置。
  • 如果找到了相同键值的节点,则替换节点的值并返回旧值。
  • 如果找到了合适的插入位置,则创建一个新的节点,将其插入到树中。
  • 插入节点后,需要进行相关的调整操作,以保持二叉搜索树的性质。
  • 最后更新树的大小和修改计数器,然后返回 null。

put 方法的时间复杂度为 O(log n),其中 n 是树中节点的数量。这是由于它需要沿着树的高度进行搜索和插入操作

    public V put(K key, V value) {
        //获取根节点 t。
        Entry<K,V> t = root;
        //如果根节点为空,表示树为空,直接创建新的节点作为根节点,并将键值对存入,然后更新树的大小和修改计数,并返回 null。
        if (t == null) {
            compare(key, key); 

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        //如果根节点不为空,根据是否存在比较器来选择使用比较器进行比较还是使用键的自然顺序进行比较。
        int cmp;
        Entry<K,V> parent;
        Comparator<? super K> cpr = comparator;
        //如果存在比较器,就根据比较器来定位节点的插入位置。通过不断与当前节点的键进行比较,如果小于当前节点的键,则向左子树查找,如果大于则向右子树查找,直到找到合适的插入位置。
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        //如果不存在比较器,就要求键实现 Comparable 接口,并根据键的自然顺序来定位节点的插入位置
        else {
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        //如果未找到与要插入键相同的节点,创建新的节点 e,将其插入到正确的位置上。根据比较结果,如果要插入的键小于当前节点的键,将新节点作为当前节点的左子节点,否则作为右子节点。
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        //插入节点后,调用 fixAfterInsertion 方法进行红黑树的平衡操作。
        fixAfterInsertion(e);
        //更新树的大小和修改计数,并返回 null。
        size++;
        modCount++;
        return null;
    }

  1. get()

在 TreeMap 类中,get(Object key) 方法用于获取指定键对应的值。

  1. 首先,判断传入的 key 是否为 null。如果是 null,则调用 getEntryForNullKey 方法来获取与 null 键关联的节点。
  2. 如果 key 不为 null,则调用 getEntry 方法来获取与给定键关联的节点。该方法会先根据比较器或键的自然顺序定位到与给定键等值或最接近的节点,然后再根据键的比较结果进一步判断要查找的节点在左子树还是右子树中。
  3. 如果找到了对应的节点,则返回该节点的值;如果没有找到,则返回 null,表示未找到匹配的键。
    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }

    final Entry<K,V> getEntry(Object key) {
        //判断是否存在比较器comparator
        if (comparator != null)
            //如果存在比较器,则调用 getEntryUsingComparator 方法使用比较器进行键的查找。
            return getEntryUsingComparator(key);
        //如果不存在比较器,则要求键实现 Comparable 接口,并将给定的键强制转换为 Comparable 类型(k)。
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        //获取根节点(root)作为起始节点(p)。
        Entry<K,V> p = root;
        //进入循环,将当前节点(p)与给定键进行比较。
        while (p != null) {
            int cmp = k.compareTo(p.key);
            //如果给定键小于当前节点的键,说明要查找的键位于当前节点的左子树,将当前节点的左子节点设为当前节点(p = p.left)。
            if (cmp < 0)
                p = p.left;
            //如果给定键大于当前节点的键,说明要查找的键位于当前节点的右子树,将当前节点的右子节点设为当前节点(p = p.right)。
            else if (cmp > 0)
                p = p.right;
            else
                //如果给定键与当前节点的键相等,找到了对应的节点,直接返回该节点(return p)。
                return p;
        }
        //如果当前节点(p)为空(不存在对应键的节点),则返回 null。
        return null;
    }


  1. remove()
    public V remove(Object key) {
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;

        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
    }

private void deleteEntry(Entry<K,V> p) {
        modCount++;
        //元素个数减一
        size--;
        // 如果被删除的节点p的左孩子和右孩子都不为空,则查找其替代节
        if (p.left != null && p. right != null) {
            // 查找p的替代节点
            Entry<K,V> s = successor (p);
            p. key = s.key ;
            p. value = s.value ;
            p = s;
        }
        Entry<K,V> replacement = (p. left != null ? p.left : p. right);
        if (replacement != null) { 
            // 将p的父节点拷贝给替代节点
            replacement. parent = p.parent ;
            // 如果替代节点p的父节点为空,也就是p为跟节点,则将replacement设置为根节点
            if (p.parent == null)
                root = replacement;
            // 如果替代节点p是其父节点的左孩子,则将replacement设置为其父节点的左孩子
            else if (p == p.parent. left)
                p. parent.left   = replacement;
            // 如果替代节点p是其父节点的左孩子,则将replacement设置为其父节点的右孩子
            else
                p. parent.right = replacement;
            // 将替代节点p的left、right、parent的指针都指向空
            p. left = p.right = p.parent = null;
            // 如果替代节点p的颜色是黑色,则需要调整红黑树以保持其平衡
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
        } else if (p.parent == null) { // return if we are the only node.
            // 如果要替代节点p没有父节点,代表p为根节点,直接删除即可
            root = null;
        } else {
            // 如果p的颜色是黑色,则调整红黑树
            if (p.color == BLACK)
                fixAfterDeletion(p);
            // 下面删除替代节点p
            if (p.parent != null) {
                // 解除p的父节点对p的引用
                if (p == p.parent .left)
                    p. parent.left = null;
                else if (p == p.parent. right)
                    p. parent.right = null;
                // 解除p对p父节点的引用
                p. parent = null;
            }
        }
    }

LinkedHashMap

LinkedHashMap是Java集合框架中的一个类,它继承了HashMap并且使用链表维护元素的插入顺序或者访问顺序。与HashMap不同的是,它可以按照元素插入的顺序或者访问的顺序来遍历元素。LinkedHashMap中的元素是按照它们被插入到映射中的顺序存储的,因此它也可以保持元素的插入顺序不变。

Set

Java中的Set接口是一种集合接口,它继承自Collection接口,表示一组不重复的元素。Set接口的特点是不允许包含重复元素,每个元素在Set中只能出现一次。


Set接口的常见实现类有:

  1. HashSet:基于哈希表的实现,不保证元素的顺序,允许使用null元素。
  2. TreeSet:基于红黑树的实现,按照元素的自然顺序或者自定义的比较器进行排序,不允许使用null元素。
  3. LinkedHashSet:基于哈希表和链表的实现,维护元素的插入顺序,允许使用null元素。

Set接口定义了一系列方法,包括:

  • 添加元素:add(element)
  • 删除元素:remove(element)
  • 判断是否包含某个元素:contains(element)
  • 获取Set的大小:size()
  • 清空Set:clear()
  • 遍历Set:使用迭代器(iterator)或者增强for循环进行遍历
import java.util.HashSet;
import java.util.Set;

public class SetExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        
        // 添加元素
        set.add("apple");
        set.add("banana");
        set.add("orange");
        
        // 判断是否包含某个元素
        boolean containsApple = set.contains("apple");
        System.out.println("Contains apple: " + containsApple);
        
        // 删除元素
        set.remove("banana");
        
        // 获取Set的大小
        int size = set.size();
        System.out.println("Set size: " + size);
        
        // 遍历Set
        for (String element : set) {
            System.out.println(element);
        }
    }
}

1. HashSet底层

HashSet是Java中的一个集合类,它实现了Set接口,并且不允许集合中存在重复元素。HashSet的底层实际上是基于HashMap实现的。


HashSet使用一个HashMap实例来存储和管理集合元素。对于HashSet中的每个元素,实际上是作为HashMap的键(key)存储的,而对应的值(value)被设置为一个常量PRESENT。HashMap的键(key)具有唯一性,因此HashSet中不允许有重复元素。由于HashSet使用了HashMap来存储元素,因此HashSet具有快速的插入、删除和查找操作。


HashSet的底层实现原理如下:

  1. 创建一个HashMap实例作为HashSet的底层数据结构。
  2. 当调用HashSet的add方法添加元素时,实际上是将元素作为HashMap的键(key)添加到HashMap中,并将对应的值(value)设置为常量PRESENT。
  3. 当调用HashSet的contains方法判断元素是否存在时,实际上是对HashMap的containsKey方法进行调用来判断是否存在对应的键。
  4. 当调用HashSet的remove方法删除元素时,实际上是将元素作为HashMap的键(key)进行删除操作。
  5. HashSet还利用了HashMap的哈希表特性,对元素进行散列存储,可以提高查找效率。

注意:

由于HashSet是基于HashMap实现的,因此HashSet并不能保证元素的顺序。元素在HashSet中的顺序是由元素的哈希值决定的,而非添加的顺序。如果需要按照顺序存储元素,可以考虑使用LinkedHashSet,它使用了链表来维护元素的插入顺序。
总结来说,HashSet的底层实现是利用HashMap来存储和管理元素,并且HashSet中的元素是无序且不允许重复的


用法:

package com.wz.collection05;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetTest {
    public static void main(String[] args) {
        //HashSet底层采用的是HashMap来存储元素,因为HashMap的key是唯一的,
        //因此,HashSet存储的元素也是唯一的。因为HashMap存储元素是无序的,因此
        //HashSet存储的元素也是无序的
        Set<String> set = new HashSet<>();
        System.out.println(set.add("a"));//true
        System.out.println(set.add("a"));//false
        System.out.println(set.add("b"));//true
        System.out.println(set.add("c"));//true
        System.out.println(set.size());//3

        for(String str : set){
            System.out.println(str);
        }

        for(Iterator<String> iter = set.iterator(); iter.hasNext();){
            String next = iter.next();
            System.out.println(next);
        }

        set.forEach(System.out::println);

        System.out.println(set.remove("a"));//true
        System.out.println(set.remove("a"));//false
    }
}

2. TreeSet

TreeSet是Java中的一个集合类,它实现了SortedSet接口,并且基于红黑树(Red-Black Tree)数据结构进行存储和管理集合元素。与HashSet不同的是,TreeSet中的元素是有序的,根据元素的自然排序或自定义比较器进行排序。


TreeSet的底层实现原理如下:

1.创建一个红黑树(Red-Black Tree)作为TreeSet的底层数据结构。
2.当调用TreeSet的add方法添加元素时,新元素将按照特定的排序规则插入到红黑树中。
3.当调用TreeSet的contains方法判断元素是否存在时,红黑树会根据排序规则进行查找。
4.当调用TreeSet的remove方法删除元素时,红黑树会对相应的节点进行删除操作。


由于TreeSet使用红黑树作为底层数据结构,它具有以下特性:

元素是有序的,按照自然排序或自定义比较器排序。

插入、删除、查找元素的时间复杂度为O(logN),其中N是集合中元素的数量。

TreeSet不允许插入空值。

TreeSet是非线程安全的,如果需要在多线程环境中使用,可以使用Collections类的synchronizedSortedSet方法或ConcurrentSkipListSet类。

需要注意的是,由于TreeSet使用红黑树作为底层数据结构,对于包含大量元素的集合,TreeSet的性能可能比HashSet稍低。因此,在选择使用HashSet还是TreeSet时,需要根据具体的需求和性能要求进行权衡。

3. LinkedHashSet

LinkedHashMap是Java集合框架中的一个实现类,它继承自HashMap类,并且在HashMap的基础上增加了按照插入顺序或者访问顺序进行迭代的功能。

与HashMap不同,LinkedHashMap在内部使用了一个双向链表来维护元素的顺序。每个元素包含一个前驱指针和一个后继指针,这样就可以按照插入顺序或者访问顺序(最近访问的元素放在最后)来迭代元素。


LinkedHashMap的主要特点包括:

  1. 保持插入顺序或访问顺序:LinkedHashMap可以按照元素的插入顺序或者最近访问的顺序进行迭代。通过构造函数可以选择按照插入顺序或者访问顺序进行迭代。

  2. 继承自HashMap:LinkedHashMap继承了HashMap的大部分功能,包括高效的查找、插入和删除操作。它使用哈希表来存储元素,具有快速的查找性能。

  3. 非线程安全:LinkedHashMap是非线程安全的,如果需要在多线程环境下使用,可以考虑使用ConcurrentLinkedHashMap或者使用Collections工具类的synchronizedMap方法包装LinkedHashMap。

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
        
        // 添加元素
        linkedHashMap.put("apple", 1);
        linkedHashMap.put("banana", 2);
        linkedHashMap.put("orange", 3);
        
        // 遍历LinkedHashMap
        for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + ": " + value);
        }
    }
}

创建了一个LinkedHashMap对象,并向其中添加了三个键值对。然后使用entrySet方法获取LinkedHashMap中的所有键值对,并通过迭代器遍历输出每个键值对的内容。由于LinkedHashMap会保持插入顺序,所以输出的结果将按照元素的插入顺序进行展示。

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

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

相关文章

Windows10下ChatGLM2-6B模型本地化安装部署教程图解

随着人工智能技术的不断发展&#xff0c;自然语言处理模型在研究和应用领域备受瞩目。ChatGLM2-6B模型作为其中的一员&#xff0c;以其强大的聊天和问答能力备受关注&#xff0c;并且最突出的优点是性能出色且轻量化。然而&#xff0c;通过云GPU部署安装模型可能需要支付相应的…

手把手带你创建微服务项目

1.先创建以下项目结构 2.在父项目中导入以下依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- Web依赖 --><dependency>&l…

关于Java集合框架的总结

关于Java集合框架的总结 本篇文章先从整体介绍了java集合框架包含的接口和类&#xff0c;然后总结了集合框架中的一些基本知识和关键点&#xff0c;并结合实例进行简单分析。当我们把一个对象放入集合中后&#xff0c;系统会把所有集合元素都当成Object类的实例进行处理。从JDK…

分享四款导航页 个人主页html源码

一、开源免费&#xff0c;可以展示很多社交账号&#xff0c;也可以更换社交账号图标指向你的网站&#xff0c;上传后即可使用 https://wwwf.lanzout.com/ik7R912s031g 二、开源免费&#xff0c;不过部署稍微麻烦点 https://wwwf.lanzout.com/iCq2u12s02wb 三、适合做成导航页面…

Android性能优化篇[谷歌官方]

网上看到了个和Android性能优化相关的系列文章&#xff0c;觉的还不错&#xff0c;和大家分享下。 在Android领域&#xff0c;性能永远是一块大头。市场对这类人才的需求也是有增不减&#xff0c;而且薪资待遇也不错。如果大家想深入学习Android某个领域&#xff0c; 那性能这块…

190 → 169,50天瘦20斤随感

一头猪瘦二十斤没有人会在意&#xff0c;但一个人猛地瘦二十斤或许就会有意思~ 从五月底到7月中旬&#xff0c;大致50天瘦了21斤。本文大致从我自己的感想、方法、减肥前后的心态及身体变化等方面来给予你一些关键信息&#xff0c;希望对你有用吧。 当你发现自己真的在一斤一斤…

react CSS :last-child 最后一个下边框线如何去掉

需求&#xff1a;调用分类接口后&#xff0c;tab的最后一个border不要横线。 代码如下 逻辑是 i是否等于books数组的长度-1。 books.map((book, i) > { return( <View style{borderBottom:idx ! dictype.length - 1 && "1px solid #ECEFF7"} key…

CentOS7 mariadb10.x 安装

1、添加mariabd yum源 vi /etc/yum.repos.d/mariadb.repo [mariadb] name MariaDB baseurl https://mirrors.tuna.tsinghua.edu.cn/mariadb/yum/10.5/centos7-amd64/ gpgkey https://mirrors.tuna.tsinghua.edu.cn/mariadb/yum/RPM-GPG-KEY-MariaDB gpgcheck 12、建立yum…

EMC学习笔记(十六)射频PCB的EMC设计(三)

射频PCB的EMC设计&#xff08;三&#xff09; 1.布线1.1 阻抗控制2.2 转角1.3 微带线布线1.4 微带线耦合器1.5 微带线功分器1.6 微带线基本元件1.7 带状线布线1.8 射频信号走线两边包地铜皮 2.其他设计考虑 1.布线 1.1 阻抗控制 PCB信号走线的阻抗与板材的介电常数、PCB结构、…

【山河送书第二期】:《零基础学会Python编程(ChatGPT版》

【山河送书第二期】&#xff1a;《零基础学会Python编程&#xff08;ChatGPT版》 前言内容简介作者简介 前言 在过去的 5 年里&#xff0c;Python 已经 3 次获得 TIOBE 指数年度大奖&#xff0c;这得益于数据科学和人工智能领域的发展&#xff0c;使得 Python 变得异常流行&am…

电脑pdf怎么转换成word文档?你不知道的几种方法

在电脑上&#xff0c;我们经常需要查阅PDF文件&#xff0c;并且PDF文件在生活中应用广泛&#xff0c;可以保存许多重要内容。有时候我们需要将PDF文件转换为Word文档&#xff0c;以便对文件内容进行编辑。幸运的是&#xff0c;在电脑上将PDF转换为Word文档非常方便&#xff0c;…

nginx实现反向代理

Nginx Nginx (“engine x”) 是一个高性能的HTTP和反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强。Nginx可以作为静态页面的web服务器&#xff0c;同时还支持CGI协议的动态语言&#xff0c;比如perl、php等。但是不支持java。Java程序只能通过与tomcat配合…

生命在于折腾——MacOS(Inter)渗透测试环境搭建

一、前景提要 之前使用的是2022款M2芯片的MacBook Air 13寸&#xff0c;不得不说&#xff0c;是真的续航好&#xff0c;轻薄&#xff0c;刚开始我了解到M芯片的底层是ARM架构&#xff0c;我觉得可以接受&#xff0c;虚拟机用的不多&#xff0c;但在后续的使用过程中&#xff0…

《MySQL》事务

文章目录 概念事务的操作属性&#xff08;aicd&#xff09; 概念 一组DML语句&#xff0c;这组语句要一次性执行完毕&#xff0c;是一个整体 为什么要有事务&#xff1f; 为应用层提供便捷服务 事务的操作 有一stu表 # 查看事务提交方式(默认是开启的) show variables like au…

智能照明及控制系统在医院建筑中的应用

摘要&#xff1a;现阶段&#xff0c;我国的社会经济的发展水平不断提高&#xff0c;为智能照明系统的发展带来了新的契机。文章主要介绍了几类智能照明系统&#xff0c;分析了其优点&#xff0c;并介绍了智能照明系统在医院建筑中的具体应用&#xff0c;具有一定的参考价值。 …

数据结构顺序表,实现增删改查

一、顺序表结构体定义 #define MAXSIZE 8 //定义常量MAXSIZE&#xff0c;表示数据元素的最大个数为8 typedef int datatype; //重定义int类型&#xff0c;分别后期修改顺序表中存储的数据类型 typedef struct {int len; //顺序表长度datatype data[MAXSIZE…

微服务架构介绍 - SpringCloud Alibaba

1. 单体架构vs微服务架构 1.1 单机架构 1.1.1 什么是单体架构 一个归档包&#xff08;例如war格式&#xff09;包含了应用所有功能的应用程序&#xff0c;我们通常称之为单体应用。架构单体应用的方法论&#xff0c;我们称之为单体应用架构。&#xff08;就是一个war包打天下&a…

Service:微服务架构的应对之道

Service 的工作原理和 LVS、Nginx 差不多&#xff0c;Kubernetes 会给它分配一个静态 IP 地址&#xff0c;然后它再去自动管理、维护后面动态变化的 Pod 集合&#xff0c;当客户端访问 Service&#xff0c;它就根据某种策略&#xff0c;把流量转发给后面的某个 Pod。 Service 使…

小程序form表单验证,validate 在更新数据以后不能验证?还是提示同样的错误

报错&#xff1a; 一直报手机号码必须填写&#xff0c;但是我已经填写了。 解决&#xff1a; 花了2个小时&#xff0c;最后发布是模式models写错了。 改完之后&#xff0c;终于提示别的错误了&#xff1a; 源码&#xff1a; //wxml <view class"welcome">欢…

一款挖掘xss漏洞的工具

xsshelp 闲着没事随便写的一个辅助挖掘xss漏洞的工具&#xff08;主要手懒为了省事&#xff0c;就把每回挖xss的一个比较好用的思路简单给用工具实现了下&#xff09; xsshelp version: 1.0.0Usage: [-ut] [-u url] [-t thread] [-h help]Options: -h this help -t intth…