Java 集合学习笔记:HashMap

news2024/11/25 22:54:19

Java 集合学习笔记:HashMap

  • UML
  • 简介
  • 阅读源码
    • 属性字段
      • 1. 静态属性
      • 2.成员属性
    • 静态内部类
      • class Node<K,V>
    • 静态工具方法
      • hash(Object key)
      • comparableClassFor(Object x)
      • compareComparables(Class<?> kc, Object k, Object x)
      • tableSizeFor(int cap)
    • 构造方法
      • HashMap(int initialCapacity, float loadFactor)
      • HashMap(int initialCapacity)
      • HashMap()
      • HashMap(Map<? extends K, ? extends V> m)
    • 成员方法列表
  • 参考资料

UML

在这里插入图片描述

简介

基于Hash tableMap接口实现。实现了 Map 定义的所有方法,并允许 keyvaluenull。(除了非线程安全和允许 null 之外,HashMapHashtable 大致相同)这个类不保证 map 的顺序;尤其是,它不能保证顺序随时间的推移保持不变。

这个实现为基本操作(getput)提供了恒定时间的性能,假设 hash 函数将元素适当地分散到桶中。在集合视图上迭代所需的时间与HashMap实例的容量(桶的数量)加上它的大小(键-值映射的数量)成正比。因此,如果迭代性能很重要,就不要将初始容量设置得太高(或加载因子设置得太低)。

HashMap 的实例有两个参数影响其性能:初始容量加载因子容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行rehash操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。

通常,默认加载因子 (0.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 getput 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

如果很多映射关系要存储在 HashMap 实例中,则相对于按需执行自动的 rehash 操作以增大表的容量来说,使用足够大的初始容量创建它将使得映射关系能更有效地存储。

注意,此实现不是同步的。如果多个线程同时访问一个哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须 保持外部同步。(结构上的修改是指添加或删除一个或多个映射关系的任何操作;仅改变与实例已经包含的键关联的值不是结构上的修改。)这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的非同步访问,如下所示:

Map m = Collections.synchronizedMap(new HashMap(...));

由所有此类的“collection 视图方法”所返回的迭代器都是快速失败 的:在迭代器创建之后,如果从结构上对映射进行修改,除非通过迭代器本身的 remove 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。

注意,迭代器的快速失败行为不能得到保证,一般来说,存在非同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException 。因此,编写依赖于此异常的程序的做法是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。

此类是 Java Collections Framework 的成员。

阅读源码

属性字段

1. 静态属性

属性默认值说明
DEFAULT_INITIAL_CAPACITY16默认的初始容量-必须是2的幂。
MAXIMUM_CAPACITY230最大容量,必须小于等于该值。且必须是2的幂。
DEFAULT_LOAD_FACTOR0.75f默认加载因子
TREEIFY_THRESHOLD8树化阈值。当向bin(桶)中添加元素时,如果 binCount >= TREEIFY_THRESHOLD - 1 则,bin将(由列表)转换为。取值范围(2, 8]
UNTREEIFY_THRESHOLD6在调整大小操作期间取消树化的阈值。应小于 TREEIFY_THRESHOLD,且最多为6
MIN_TREEIFY_CAPACITY64可以对容器进行树化的最小表容量。(否则,如果一个bin中有太多的节点,则会调整表的大小。)应该至少是4 * TREEIFY_THRESHOLD,以避免调整大小和树化阈值之间的冲突。

2.成员属性

默认都是 null

属性说明
transient Node<K,V>[] table表,在第一次使用时初始化,并根据需要调整大小。分配时,长度总是2的幂。(我们还允许某些操作的长度为0,以允许当前不需要的引导机制。)
transient Set<Map.Entry<K,V>> entrySet保存缓存的 entrySet()。注意,AbstractMap 字段用于 keySet()values()
transient int sizeMap 中包含的键-值对的数量。
transient int modCount结构修改是指改变 HashMap 中的映射数量或以其他方式修改其内部结构(例如,重新哈希)的修改。该字段用于使 HashMap 集合视图上的迭代器快速失败。(见ConcurrentModificationException)。
int threshold要调整大小的下一个大小值( 容量 * 加载因子)。
final float loadFactor哈希表的加载因子。
———————————————————

静态内部类

class Node<K,V>

基本的哈希 bin (桶)节点,用于大多数键值对。(参见下面的TreeNode子类,以及LinkedHashMap的Entry子类。)

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash; // 散列值。通过静态方法 hash(Object key) 计算 key 生成的
        final K key;	// 没错就是用我算出的 hash
        V value;		// 本节点保存的元素值
        Node<K,V> next; // 指向下一节点的指针

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }
		// 更新值后,返回原值。
        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
		// 1. 如果地址相等,直接 true
		// 2. 如果 o 是 Map.Entry(键值对实体)的实例,且 key、value 都一样则 true
		// 3. 否则不相等 false
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

静态工具方法

访问修饰符&返回类型方法描述
static final inthash(Object key)获取 key 的 hash 值。为了尽量避免碰撞,使用 异或位移。是出于性能考虑。
static Class<?>comparableClassFor(Object x)如果x的形式是Class C implements Comparable<C> 返回它的类的类型。否则为空。
static intcompareComparables(Class<?> kc, Object k, Object x)如果 x的类型kc 就返回 k.compareTo(x) 的结果,否则返回 0
static final inttableSizeFor(int cap)返回大于 cap(给定目标容量)的最小 2 次幂数。
—————————————————————

hash(Object key)

获取 key 的 hash 值。为了尽量避免碰撞,使用 异或位移。是出于性能考虑。

  • test
@Test
public void hashCodeTest(){
    int h = 0b11111111111111110000000000000000;     // 0b开头表示二进制数
    int i = h >>> 16;                               // 无符号右移16位(包括符号位一起移)
    log.info("{}", Integer.toBinaryString( i ));    // 00000000000000001111111111111111 原本高位的16个1都移到了左边,左边空出的位置补0
    int hash = h ^ i;                               // 异或运算
    log.info("{}", Integer.toBinaryString( hash )); // 11111111111111111111111111111111 i高16位没东西,直接照搬 h,低16位,不同为1,相同为 0
}
  • hash(Object key)
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
  • public native int hashCode(); Object 的原生方法:返回此对象的 hash 值。
  • 为何要使用异或位移来减少碰撞?

comparableClassFor(Object x)

如果x的形式是Class C implements Comparable<C> 返回其类的类型。否则为空。

  • test
    例如:当 x 的类型 C 和比较器的参数类型 Comparable<C> 一样时就返回 C
// 形式为 Class C implements Comparable<C>
Class C implements Comparable<C>;
C c = new C;
Class<?> clazz = comparableClassFor(c);
System.out.println(clazz.getName()); // C
// Class C implements Comparable<如果这里不是C> 返回 null
  • comparableClassFor(Object x)
static Class<?> comparableClassFor(Object x) {
	// 如果 x 是 Comparable 的实例。如果是继续,否则返回 null;
    if (x instanceof Comparable) {
    
        Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
        // 如果 x 是个 String 直接返回类型。
        if ((c = x.getClass()) == String.class) // bypass checks
            return c;
        // 获取 c 所实现的接口们(可能有多个所以放数组里)。如果不为 null 继续,否则返回 null;
        if ((ts = c.getGenericInterfaces()) != null) {
        	// 逐个遍历接口类型
            for (int i = 0; i < ts.length; ++i) {
                if (
                	// 1. 如果此接口 t 是某种 ParameterizedType(参数化类型,如 Collection<String>)
                	((t = ts[i]) instanceof ParameterizedType)
                	// 2. 并且,接口 t 的类型正好是 Comparable(为了调用 getRawType() 获取类型,做了强转)
                    && ((p = (ParameterizedType)t).getRawType() == Comparable.class)
                    // 3. 并且,获取 p 的参数类型数组。不为 null。(Comparable<T>就是这里替换 T 的实参)
                    && (as = p.getActualTypeArguments()) != null
                    // 4. 并且,只有 1 个
                    && as.length == 1 
                    // 5. 并且,Comparable<参数> 中的 ‘参数’ == 给定的 x 的类型。
                    && as[0] == c
                 ) 
                 return c;
            }
        }
    }
    return null;
}

compareComparables(Class<?> kc, Object k, Object x)

如果 x的类型kc 就返回 k.compareTo(x) 的结果,否则返回 0
此方法是要配合上面的 comparableClassFor(Object x) 一起用的。

  • test
@Test
public void compareComparablesTest(){
    String k = "jerry1";
    String x = "jerry2";
    Class<?> kc = comparableClassFor(k);
    int i = compareComparables(kc, k, x);
    log.info("{}", i); // -1
}
  • compareComparables(Class<?> kc, Object k, Object x)

k:就是 key,比如类型是我们最见的“字符串”。String 实现了 Comparable<String>
kc : 通过 comparableClassFor(k) 区取 k 实现的 Comparable<T> 中的实参。在 HashMap 的源码 findtreeifyputTreeVal 这些方法中能看到它的身影。kc 都有判断 null 然后才使用。

@SuppressWarnings({"rawtypes","unchecked"}) // 压制强转警告
static int compareComparables(Class<?> kc, Object k, Object x) {
	// 以下情况中假设 k、x 的类型都是 String
	// 1. x 为 null 直接返回 0 (表示比个毛)
	// 2. kc 是从 k 上获取的比较器(Comparable<String>)的参数的类型(String.class)。
	//    如果 k 没有实现 Comparable<String> 则 kc 为 null,否则 kc 为 String.class
	// 3. x.getClass() != kc 意思是:如果 k 没有实现 Comparable<String> 比较器,就没法比,直接返回 0
	//    换句话说只有 k 实现了 Comparable<X> 才会执行到 ((Comparable)k).compareTo(x) 这里。
    return (x == null 
    		|| x.getClass() != kc ? 0 : ((Comparable)k).compareTo(x));
}

tableSizeFor(int cap)

返回大于 cap(给定目标容量)的最小 2 次幂数。

  • test
    以 cap = 50 为例:
@Test
public void tableSizeForTest(){
    int cap = 50;
    int n = cap - 1;	// n: 49。
    int MAXIMUM_CAPACITY = 1 << 30; // 1_073_741_824
    //int x,y;
    //log.info("原值={}; {} = {} | {}; Binary: {} = {} | {} ", x=y=n, x |= x >>> 1, y, y>>>1,Integer.toBinaryString(x), Integer.toBinaryString(y), toBinary(y>>>1, 6));
    n |= n >>> 1;       // 原值=49; 57 = 49 | 24; Binary: 111001 = 110001 | 011000
    n |= n >>> 2;       // 原值=57; 61 = 57 | 28; Binary: 111101 = 111001 | 011100
    n |= n >>> 4;       // 原值=63; 63 = 63 | 31; Binary: 111111 = 111111 | 011111
    n |= n >>> 8;       // 原值=63; 63 = 63 | 31; Binary: 111111 = 111111 | 011111
    n |= n >>> 16;      // 原值=63; 63 = 63 | 31; Binary: 111111 = 111111 | 011111
    n = (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    System.out.println(n); // 64
}

从下而定个例子也可以看出,当有 6 位时,第三次移动时,就已经得到全是1的效果了。

// ========================= 6位 =========================
100000
0100000      // 第1次
------------------
110000
00110000	 // 第2次
------------------
111100
0000111100	 // 第3次
------------------
111111 		 // 6位第次就搞定了

// ========================= 再来个全的32位 =========================
10000000000000000000000000000000
01000000000000000000000000000000 	// >>> 1
------------------------------------
11000000000000000000000000000000	// |
00110000000000000000000000000000	// >>> 2
------------------------------------
11110000000000000000000000000000	// |
00001111000000000000000000000000	// >>> 4
------------------------------------
11111111000000000000000000000000	// |
00000000111111110000000000000000	// >>> 8
------------------------------------
11111111111111110000000000000000	// |
00000000000000001111111111111111	// >>> 16
------------------------------------
11111111111111111111111111111111

cap:目标容量传进来前确保 >= 0

static final int tableSizeFor(int cap) { // cap = 50
    int n = cap - 1;	// 此处 -1 确保当正好是2的二次幂时,最后的 +1 能还原此数。
    // 这一通 >>> 与 | 配合下来,能得到原最高位后所有位都变成1.
    // 如: 100000 to 111111; 101010 to 111111;
    n |= n >>> 1;		
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    // 小于0直接返回 1
    // 如果大于最大值直接返回最大值,否则当前值 +1 返回。
    // +1 能保存是 2的二次幂。因为最高位后所有都是1时,再+1,肯定是一个2的倍数。
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

构造方法

访问修饰符&返回类型方法描述

HashMap(int initialCapacity, float loadFactor)

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and load factor.
 *
 * @param  initialCapacity the initial capacity
 * @param  loadFactor      the load factor
 * @throws IllegalArgumentException if the initial capacity is negative
 *         or the load factor is nonpositive
 */
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}

HashMap(int initialCapacity)

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and the default load factor (0.75).
 *
 * @param  initialCapacity the initial capacity.
 * @throws IllegalArgumentException if the initial capacity is negative.
 */
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

HashMap()

/**
 * Constructs an empty <tt>HashMap</tt> with the default initial capacity
 * (16) and the default load factor (0.75).
 */
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

HashMap(Map<? extends K, ? extends V> m)

/**
 * Constructs a new <tt>HashMap</tt> with the same mappings as the
 * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
 * default load factor (0.75) and an initial capacity sufficient to
 * hold the mappings in the specified <tt>Map</tt>.
 *
 * @param   m the map whose mappings are to be placed in this map
 * @throws  NullPointerException if the specified map is null
 */
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}

  • putMapEntries(Map<? extends K, ? extends V> m, boolean evict)
/**
 * Implements Map.putAll and Map constructor
 *
 * @param m the map
 * @param evict false when initially constructing this map, else
 * true (relayed to method afterNodeInsertion).
 */
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
    int s = m.size();
    if (s > 0) {
        if (table == null) { // pre-size
            float ft = ((float)s / loadFactor) + 1.0F;
            int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                     (int)ft : MAXIMUM_CAPACITY);
            if (t > threshold)
                threshold = tableSizeFor(t);
        }
        else if (s > threshold)
            resize();
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
            K key = e.getKey();
            V value = e.getValue();
            putVal(hash(key), key, value, false, evict);
        }
    }
}

成员方法列表

访问修饰符&返回类型方法描述
voidclear()Removes all of the mappings from this map.
Objectclone()Returns a shallow copy of this HashMap instance: the keys and values themselves are not cloned.
Vcompute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping).
VcomputeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.
VcomputeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)If the value for the specified key is present and non-null, attempts to compute a new mapping given the key and its current mapped value.
booleancontainsKey(Object key)Returns true if this map contains a mapping for the specified key.
booleancontainsValue(Object value)Returns true if this map maps one or more keys to the specified value.
Set<Map.Entry<K,V>>entrySet()Returns a Set view of the mappings contained in this map.
voidforEach(BiConsumer<? super K,? super V> action)Performs the given action for each entry in this map until all entries have been processed or the action throws an exception.
Vget(Object key)Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
VgetOrDefault(Object key, V defaultValue)Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.
booleanisEmpty()Returns true if this map contains no key-value mappings.
Set<K>keySet()Returns a Set view of the keys contained in this map.
Vmerge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value.
Vput(K key, V value)Associates the specified value with the specified key in this map.
voidputAll(Map<? extends K,? extends V> m)Copies all of the mappings from the specified map to this map.
VputIfAbsent(K key, V value)If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value.
Vremove(Object key)Removes the mapping for the specified key from this map if present.
booleanremove(Object key, Object value)Removes the entry for the specified key only if it is currently mapped to the specified value.
Vreplace(K key, V value)Replaces the entry for the specified key only if it is currently mapped to some value.
booleanreplace(K key, V oldValue, V newValue)Replaces the entry for the specified key only if currently mapped to the specified value.
voidreplaceAll(BiFunction<? super K,? super V,? extends V> function)Replaces each entry’s value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception.
intsize()Returns the number of key-value mappings in this map.
Collection<V>values()Returns a Collection view of the values contained in this map.

参考资料

Class HashMap<K,V>

笑虾:Java 学习笔记 HashMap 中的 hash 方法为何要进行异或和位移?

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

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

相关文章

电梯物联网网关软硬件一体化解决方案

电梯物联网监测平台&#xff0c;基于边缘计算智能监测设备全天候、全自动监测电梯的运行。通过采集电梯实时运行传感数据&#xff0c;建立运行状态关键数据标准&#xff0c;基于AI机器学习算法&#xff0c;采用大数据分析计算&#xff0c;对电梯故障、困人等事件实时报警&#…

solr自定义定制自带core添加分词器,解决镜像没有权限问题

因为solr要安装自定义的分词器 就打算在原有基础上提前放好,直接启动就有core 第一步获取默认配置 方法一 docker安装solr 这个帖子中 1、安装镜像 docker pull solr:8.11.1 2、新建目录 mkdir -p /home/apps/solr 3、复制配置文件 运行一个临时solr docker run --name solr…

14.HTML和CSS 02

文章目录一、HTML标签&#xff1a;表单标签1、概念2、form标签3、表单项标签4、案例二、CSS&#xff1a;页面美化和布局控制1、概念2、好处3、CSS的使用&#xff1a;CSS与html结合方式4、css语法5、选择器6、属性案例一、HTML标签&#xff1a;表单标签 1、概念 表单标签是用于…

integral函数Opencv源码理解-leetcode动态规划的使用场景

前言 Opencv有一个integral()函数&#xff0c;也就是积分图算法。有三种积分图类型&#xff0c;求和&#xff08;sum&#xff09;&#xff0c;求平方和(sqsum)&#xff0c;求旋转45和(titled)。根据名字可知道&#xff0c;前两个是统计输出每个坐标的左上方像素和、左上方像素平…

pexpect 自动交互输入

pexpect 为 python 内置库&#xff0c;在 linux 上执行的&#xff0c;win 执行会报错 主要用于执行命令后自动输入&#xff0c;例如要执行 sql 去修改全局变量&#xff1a; mysql -uroot -p -h127.0.0.1 -e"set gloabl max_prepared_stmt_count1000000;" 这时候会…

实时数据平台设计

1 相关概念背景 1.1 从现代数仓架构角度看实时数据平台 现代数仓由传统数仓发展而来&#xff0c;对比传统数仓&#xff0c;现代数仓既有与其相同之处&#xff0c;也有诸多发展点。首先我们看一下传统数仓&#xff08;图1&#xff09;和现代数仓&#xff08;图2&#xff09;的…

基于springboot和vue的IT内部电脑报修服务系统设计与实现-计算机毕业设计源码+LW文档

it内部设备服务系统设计与实现 摘 要 it内部设备服务系统将传统的网络服务方式与最新的互联网技术相结合&#xff0c;使用方便快捷&#xff0c;有利于设备维修部门规范管理&#xff0c;提高网络维修部门的工作效率&#xff0c;在技术、态度等多方面提高维修部门服务质量。因此…

Oracle表空间、用户详解

目录新建连接三者关系表空间创建表空间修改表空间和数据文件修改数据文件容量新增表空间的数据文件重命名数据文件修改表空间状态修改数据文件状态删除表空间查询用户创建删除查询修改新建连接 工具选择&#xff1a; 我们一般会选择一个工具来连接本地的Oracle&#xff0c;而我…

老男孩k8s笔记

1.docker常用操作&#xff0c;挂载&#xff0c;环境变量&#xff0c;容器内安装应用&#xff0c;提交镜像 2.trefik部署&#xff1a; k8s部署traefik_weixin_30916125的博客-CSDN博客 3.删除节点后重新加入 k8s node节点删除并重新加入_人生匆匆的博客-CSDN博客 4.mariDB配置…

streamlit+ndraw进行可视化训练深度学习模型

简介 如果你喜欢web可视化的方式训练深度学习模型&#xff0c;那么streamlit是一个不可错过的选择&#xff01; 优点&#xff1a; 提供丰富的web组件支持嵌入python中&#xff0c;简单易用轻松构建一个web页面&#xff0c;按钮控制训练过程 本文使用streamlit进行web可视化…

会议管理系统SSM记录(一)

目录&#xff1a; &#xff08;1&#xff09;环境搭建 &#xff08;2&#xff09;整合MyBatis &#xff08;1&#xff09;环境搭建 添加&#xff1a;package 配置成web的结构&#xff1a; pom先加入springmvc的依赖就可以实现spring和springmvc的整合 pom.xml中加入依赖&am…

接口的定义与实现

声明类的关键字是class&#xff0c;声明接口的关键字是interface 1.介绍 普通类&#xff1a;只有具体实现 抽象类&#xff1a;具体实现和规范&#xff08;抽象方法&#xff09;都有 接口&#xff1a;只有规范 |自己无法写方法&#xff0c;专业的约束 接口就是规范&#xff0c;…

MATLAB | 全网唯一 MATLAB双向弦图(有向弦图)绘制

先赞后看&#xff0c;养成习惯~~ 先赞后看&#xff0c;养成习惯~~ 先赞后看&#xff0c;养成习惯~~ 绘制效果 下面这款弦图我已经出了很久了&#xff0c;也陆陆续续增添了新的功能和修了一些bug&#xff1a; 甚至还用它做出了一些复刻&#xff0c;分成两组的弦图有了后就有很多…

【仿真建模】AnyLogic入门基础教程 第一课

文章目录一、AnyLogic介绍二、设置2.1 设置中文三、新建项目四、行人库介绍五、创建新行人六、切换3D视角七、增加墙八、行人密度图一、AnyLogic介绍 二、设置 2.1 设置中文 三、新建项目 四、行人库介绍 点击面板&#xff0c;选择第三个图标&#xff0c;就是行人库 行人库分…

【第五部分 | JS WebAPI】4:八千字详解 “事件·高级篇”

目录 | 概述 | 注册事件的两种方式 | 删除事件的两种方式 | 事件对象【重要】 事件对象简介和声明 e.target 和 this 的区别 [ 事件对象 的常用属性方法 ] | Dom事件流 什么是Dom事件流&#xff1f; 阻止默认行为 阻止事件冒泡 利用事件冒泡进行事件委托 | 常用的鼠…

1、Git相关操作

目录 一、远程库的拉取 二、远程库创建分支 声明&#xff1a;需要有一定的GIt基础&#xff0c;如果不懂可以自行查看个人学习的Git笔记或者可以通过其他途径学习Git 一、远程库的拉取 步骤&#xff1a; 先创建一个空的文件夹在创建的文件夹中使用git init 命令来初始化本地…

频域中的后门攻击论文笔记

文章一&#xff1a;Rethinking the Backdoor Attacks’ Triggers: A Frequency Perspective 文章贡献&#xff1a; 在频域上对现有的 backdoor trigger 进行分析&#xff0c;发现常见 trigger 存在 high-frequency artifacts 的问题。对这些 artifacts 进行了详细的分析展示了…

什么是中间件

一、什么是中间件 中间件&#xff08;Middleware&#xff09;是处于操作系统和应用程序之间的软件&#xff0c;也有人认为它应该属于操作系统中的一部分。人们在使用中间件时&#xff0c;往往是一组中间件集成在一起&#xff0c;构成一个平台&#xff08;包括开发平台和运行平…

企业内训app源码,在线培训小程序,随时随地想学就学

近年来&#xff0c;在线学习逐渐被广泛应用于人才培养领域。公司要想长远发展&#xff0c;内部培训必不可少。公司的发展离不开公司整体员工的进步&#xff0c;而人员管理往往是公司管理中最重要也最难的一个环节。许多公司开始通过企业内训app源码开发来优化公司人员管理方式、…

基于PHP+MySQL学生信息管理系统的设计与实现

我国是一个高等教育逐渐普及的国度&#xff0c;相应的每年也有上百万的大学生入校&#xff0c;如此庞大的学生数量如何进行更加科学的管理是教育工作者一直关心的一个问题&#xff0c;为了能够实现高校对学生信息管理的科学化&#xff0c;信息化&#xff0c;我们开发了本基于PH…