【Java集合篇】HashMap的remove方法是如何实现的?

news2024/11/19 12:41:41

在这里插入图片描述

HashMap的remove方法是如何实现的

  • ✔️典型解析
  • ✔️拓展知识仓
    • ✔️HashMap的remove方法的注意事项
    • ✔️HashMap的remove方法的参数类型
    • ✔️ 删除键和值的参数类型有什么区别
      • ✔️删除键值对的场景是什么
    • ✔️HashMap remove方法是阻塞队列的吗
    • ✔️HashMap remove方法是线程安全的吗
      • ✔️什么是分段锁技术(上面提到在这里做简单的概括,随后细说)
    • ✔️HashMap remove方法的优缺点
    • ✔️HashMap的remove方法怎么实现同步
  • ✔️源码解读


✔️典型解析


下面是JDK 1.8中HashMap的remove方法的简要实现过程:

1 . 首先,remove方法会计算键的哈希值,并通过哈希值计算出在数组中的索引位置。


2 . 如果该位置上的元素为空,说明没有找到对应的键值对,直接返回null。


3 . 如果该位置上的元素不为空,检查是否与当前键相等,如果相等,那么将该键值对删除,并返回该键值对的值。


4 . 如果该位置上的元素不为空,但也与当前键不相等,那么就需要在链表或红黑树中继续查找。


5 . 遍历链表或者红黑树,查找与当前键相等的键值对,找到则将该键值对删除,并返回该键值对的值,否则返回null。


HashMap 是 Java 中的一种数据结构,它实现了 Map 接口。HashMap 的 remove 方法主要用于从 map 中删除指定的键值对。以下是 HashMap 的 remove 方法的基本实现:

public V remove(Object key) {
    Node<K,V> e;
    if ((e = removeNode(hash(key), key)) == null)
        return null;
    V oldVal = e.value;
    modCount++;
    size--;
    return oldVal;
}

这段代码做了以下几件事情:

  1. removeNode(hash(key), key):这是 HashMap 的核心部分,它尝试删除给定键的节点。如果这个键存在,那么对应的节点就会被删除。这个方法需要两个参数:一个是键的哈希值,另一个是键本身。哈希值用于在数组中定位节点,而键用于在链表中定位要删除的节点。
  2. e = null:如果给定的键不存在于 map 中,那么 removeNode 方法将返回 null。在这种情况下,remove 方法也将返回 null
  3. V oldVal = e.value:如果给定的键存在于 map 中,那么对应的节点将被删除,并且节点的值将被存储在 oldVal 变量中。这个值稍后将被返回。
  4. modCount++:这是对修改计数器的递增。这个计数器用于检测 map 的结构是否在迭代过程中被修改。如果 map 在迭代过程中被修改,那么迭代器将抛出 ConcurrentModificationException。
  5. size--:这是对 map 大小的递减。因为一个键值对已经被删除,所以 map 的大小必须减少。
  6. return oldVal:最后,方法返回被删除的键值对的值。

HashMap的remove方法是通过删除特定键对应的节点来实现的。HashMap中的每个元素实际上是一个Node对象,它包含键值对(key-value pair)。在remove方法中,首先通过哈希值和键来定位要删除的节点。具体来说,首先计算出键的哈希值,然后使用这个哈希值在HashMap的数组中找到对应的索引位置。然后,在这个索引位置的链表中,通过键来找到要删除的节点。


一旦找到了要删除的节点,就将它从链表中移除,并返回该节点的值。同时,还需要更新哈希表的两个关键属性:哈希表的长度和哈希表的容量。


此外,HashMap的remove方法还需要处理并发修改异常的问题。如果多个线程同时修改HashMap,就可能出现ConcurrentModificationException异常。为了避免这个问题,当一个元素被删除后,需要将modCount(修改计数器)加一,以便在迭代过程中检测到HashMap的结构是否被修改。


这就是HashMap的remove方法的基本实现过程。需要注意的是,这个过程可能会根据不同的Java版本和不同的HashMap实现有所不同。


✔️拓展知识仓


✔️HashMap的remove方法的注意事项


使用HashMap的remove方法时,需要注意以下几点:

  1. 线程安全:在多线程环境下,如果多个线程同时调用remove方法删除哈希表中的元素,不会出现线程安全问题,因为ConcurrentHashMap是线程安全的。

  1. 返回值:remove方法返回被删除元素对应的value。需要注意的是,如果不存在该key,则返回值为null。因此,在程序中使用remove方法时,需要对返回值进行严格的判断。

  1. 性能考虑:由于HashMap是非同步的,因此在高并发情况下,如果不进行外部同步,可能会遇到数据不一致的问题。

  1. null值:HashMap允许使用null作为键和值。调用remove方法时,要特别注意是否可能删除一个null值。

  1. 并发修改异常:如果在迭代过程中对HashMap进行修改(包括使用remove方法),则可能会抛出ConcurrentModificationException。如果需要遍历并可能修改HashMap,建议使用Iterator进行操作。

  1. 初始容量和负载因子:在创建HashMap时,需要设置初始容量和负载因子。初始容量决定了哈希表的大小,而负载因子决定了何时重新哈希。如果预计存储的键值对数量很大,可能需要设置较大的初始容量和负载因子以优化性能。

  1. 内存回收:删除操作不会立即回收内存,需要等到垃圾回收机制运行时才会释放内存。

  1. 其他操作的影响:除了remove方法外,其他操作如put、get等也可能影响HashMap的性能和行为。在设计程序时,需要考虑各种操作的组合和顺序。

使用HashMap的remove方法时,需要注意多线程环境下的线程安全、返回值的处理、性能优化、null值的处理、并发修改异常的处理、初始容量和负载因子的设置、内存回收以及与其他操作的协同工作等问题。


✔️HashMap的remove方法的参数类型


HashMap的remove方法有两种参数类型:

  1. remove(Object key):以键为参数的remove方法,用于删除指定键的键值对。如果该键存在于map中,对应的键值对将被删除并返回该键的值。如果该键不存在于map中,返回null。

  2. remove(Object key, Object value):以键和值为参数的remove方法,用于删除指定键和值的键值对。只有当键和值都匹配时,对应的键值对才会被删除。如果成功删除了键值对,返回true;否则返回false。

这两种remove方法都是在调用内部的removeNode方法进行节点删除,只是传入的参数不同。

看 一个Demo,简单的项目案例:



import java.util.HashMap;  
import java.util.Scanner;  

/**
*   如何使用HashMap的remove方法来管理一个虚构的电子商务网站的库存
*/  
public class InventorySystem {  
    public static void main(String[] args) {  
        // 创建一个HashMap来存储商品库存  
        HashMap<String, Integer> inventory = new HashMap<>();  
  
        // 添加初始商品库存  
        inventory.put("Laptop", 10);  
        inventory.put("Smartphone", 20);  
        inventory.put("Tablet", 5);  
  
        // 创建一个Scanner对象,从控制台读取输入  
        Scanner scanner = new Scanner(System.in);  
  
        // 循环处理用户输入,直到用户选择退出  
        while (true) {  
            // 打印菜单选项给用户  
            System.out.println("请选择操作:");  
            System.out.println("1. 添加商品");  
            System.out.println("2. 删除商品");  
            System.out.println("3. 查看库存");  
            System.out.println("4. 退出系统");  
  
            // 读取用户输入的选择  
            int choice = scanner.nextInt();  
  
            switch (choice) {  
                case 1: // 添加商品  
                    String productName = scanner.next();  
                    int quantity = scanner.nextInt();  
                    inventory.put(productName, quantity);  
                    System.out.println("商品已添加到库存。");  
                    break;  
                case 2: // 删除商品  
                    String productToRemove = scanner.next();  
                    if (inventory.containsKey(productToRemove)) {  
                        int removedQuantity = inventory.remove(productToRemove);  
                        System.out.println("删除了 " + removedQuantity + " 个 " + productToRemove + "。");  
                    } else {  
                        System.out.println("库存中没有找到 " + productToRemove + "。");  
                    }  
                    break;  
                case 3: // 查看库存  
                    System.out.println("当前库存:");  
                    for (String product : inventory.keySet()) {  
                        System.out.println(product + " - " + inventory.get(product) + "个");  
                    }  
                    break;  
                case 4: // 退出系统  
                    System.out.println("感谢使用库存系统!");  
                    System.exit(0); // 退出程序  
                    break;  
                default: // 如果用户输入无效选项,提示用户重新输入  
                    System.out.println("无效的选择,请重新输入。");  
            }  
        }  
    }  
}

案例中,创建一个虚构的电子商务网站的库存管理系统。我们使用HashMap来存储商品和它们的数量。用户可以通过控制台菜单选择不同的操作,如添加商品、删除商品、查看库存或退出系统。根据用户的选择,程序将使用HashMap的put方法添加商品、使用remove方法删除商品、打印库存情况或者结束程序。通过这种方式,我们演示了如何使用HashMap的remove方法来管理一个复杂的项目案例。


✔️ 删除键和值的参数类型有什么区别


HashMap的remove方法有两种参数类型,它们的主要区别在于删除键值对的条件不同。

  1. remove(Object key):这个参数类型的remove方法用于删除指定键的键值对。它只检查键是否存在于map中,如果存在,则删除对应的键值对并返回该键的值;如果不存在,则返回null。这个方法只关心键是否存在,而不关心值的内容。

  1. remove(Object key, Object value):这个参数类型的remove方法用于删除指定键和值的键值对。它同时检查键和值是否匹配,只有当键和值都匹配时,对应的键值对才会被删除。这个方法不仅关心键是否存在,还关心值的内容是否匹配。

这两种参数类型的remove方法在使用上有不同的场景和需求。如果你只需要删除指定键的键值对,无论值的内容如何,可以使用remove(Object key)方法。如果你需要同时考虑键和值的内容是否匹配,可以使用remove(Object key, Object value)方法。


✔️删除键值对的场景是什么


删除键值对的场景通常出现在需要更新或删除存储在数据结构中的数据时。在HashMap中,键值对表示一种映射关系,即通过键可以快速找到对应的值。因此,在需要更新或删除某个键对应的值时,就可以使用删除键值对的方法。

如,在数据库操作中,可以根据主键(键)快速定位到相应的记录(值),然后进行删除或更新操作。在缓存系统中,可以使用键值对存储缓存数据,当某个键不再需要时,就可以通过删除键值对来释放缓存空间。

在其他数据结构中,如数组、链表等,删除键值对的场景可能不太常见,因为这些数据结构通常只关注元素的添加、删除和查找等操作,而不是关注键值对的关系。

总之,删除键值对的场景通常出现在需要维护键和值之间映射关系的数据结构中,如HashMap等。在这些场景中,删除键值对可以快速定位并更新或删除相应的数据,提高数据操作的效率和准确性。


✔️HashMap remove方法是阻塞队列的吗


HashMapremove 方法不是阻塞队列的。HashMap是一种基于数组和链表的数据结构,用于存储键值对映射关系。它提供了快速的插入、删除和查找操作。

阻塞队列是一种特殊类型的队列,当队列为空时,获取元素的线程将会阻塞,直到队列中有元素可用。同样,当队列已满时,尝试添加元素的线程也将阻塞,直到队列有空余空间。

HashMap本身并不具备阻塞队列的特性,它的remove方法只是用于删除指定键的键值对。如果需要使用阻塞队列,可以考虑使用Java提供的BlockingQueue接口及其实现类,如ArrayBlockingQueueLinkedBlockingQueue等。

总之,HashMap的remove方法不是阻塞队列的,它只是用于删除键值对。如果需要使用阻塞队列,建议使用Java提供的BlockingQueue接口及其实现类。


首先,回顾一下HashMapremove方法。这是一个非同步的方法,它从哈希表中删除指定的键值对。如果哈希表中包含指定的键值对,则返回该键值对的值;否则,返回null。这个方法不是线程安全的,因此在多线程环境中使用时需要额外的同步措施。

下面看一个Demo,说明HashMapremove方法不是阻塞的,以及如何使用BlockingQueue实现阻塞删除操作:

import java.util.HashMap;

public class HashMapExample {
    public static void main(String[] args) {
        // 创建一个HashMap
        HashMap<String, String> map = new HashMap<>();

        // 添加元素到HashMap中
        map.put("key1", "value1");
        map.put("key2", "value2");
        map.put("key3", "value3");

        // 删除一个元素
        String removedValue = map.remove("key2");
        if (removedValue != null) {
            System.out.println("成功删除了键为\"key2\"的元素,值为\"" + removedValue + "\"。");
        } else {
            System.out.println("未找到键为\"key2\"的元素。");
        }

        // 打印剩余的元素
        System.out.println("剩余的元素:");
        for (String key : map.keySet()) {
            System.out.println(key + " - " + map.get(key));
        }
    }
}

现在,看看如何使用BlockingQueue实现阻塞删除操作。BlockingQueue是一个线程安全的队列接口,它提供了阻塞的插入和删除操作。我们可以使用BlockingQueuetake方法来阻塞地删除并返回队列的头元素。如果队列为空,该方法将阻塞等待直到有元素可用。

接下来这个Demo,演示如何使用BlockingQueue实现阻塞删除操作:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueExample {
    public static void main(String[] args) throws InterruptedException {
        // 创建一个BlockingQueue实例
        BlockingQueue<String> queue = new LinkedBlockingQueue<>();

        // 添加元素到队列中
        queue.put("item1");
        queue.put("item2");
        queue.put("item3");

        // 阻塞地删除并返回队列的头元素
        String removedItem = queue.take(); // 阻塞等待直到有元素可用
        System.out.println("成功删除了元素\"" + removedItem + "\"。");
    }
}

通过这个Demo,可以看到BlockingQueuetake方法会阻塞等待直到有元素可用,然后删除并返回队列的头元素。这与HashMapremove方法不同,后者是非阻塞的,并且不会等待元素可用。如果你需要在多线程环境中安全地删除元素,并希望操作是阻塞的,你应该使用BlockingQueue而不是HashMap


✔️HashMap remove方法是线程安全的吗


HashMap的remove方法不是线程安全的。在多线程环境下,如果没有适当的同步措施,使用HashMap的remove方法可能会导致数据不一致或其他并发问题。


在Java中,HashMap是一个非同步的类,这意味着它的操作(包括remove方法)默认情况下是线程不安全的。如果你需要在多线程环境中安全地删除元素,应该考虑使用线程安全的集合类,如ConcurrentHashMap


上一篇谈HashMap的get方法时有谈,可参考!!!


ConcurrentHashMap是线程安全的,它提供了高性能的并发访问能力,适用于高并发环境。ConcurrentHashMap使用分段锁技术来实现线程安全,允许多个线程同时访问不同的段(Segment),从而提高了并发性能。


因此,一个线程安全的集合类来安全地删除元素,应该使用ConcurrentHashMap而不是HashMap


✔️什么是分段锁技术(上面提到在这里做简单的概括,随后细说)


分段锁技术是一种用于实现并发数据结构的锁策略,它将数据结构分成多个段,每个段都有自己的锁。具体来说,分段锁技术将数据分成一段一段的存储,然后给每一段数据配一把锁。当一个线程需要访问某个段的数据时,只需要获取该段对应的锁,而不会影响其他段的操作。这样可以减小锁的粒度,从而提高并发性能。


在具体实现上,分段锁技术将数据结构划分为多个段,每个段对应一个锁。当一个线程需要访问某个段的数据时,会先通过某种机制(如散列函数)确定该段数据的存储位置,然后获取该段对应的锁。这样,不同的线程可以同时访问不同的段数据,从而实现更高的并发性。


分段锁技术的优点包括:

  1. 并发性高:由于每个段都有自己的锁,不同的线程可以同时访问不同的段数据,提高了并发性能。
  2. 细粒度控制:通过将数据结构划分为多个段,可以更灵活地控制对数据的访问权限,提高了系统的可扩展性和灵活性。
  3. 更少的争用:如果数据分布比较均匀,每个锁锁住的数据区域不会太大,减少了锁的争用。

分段锁技术的缺点包括:

  1. 空间开销较大:需要为每个锁分配一定的内存空间,如果锁过多,会占用较多的资源。
  2. 管理复杂:需要管理和维护每个锁的状态和状态变化,增加了管理复杂性。

分段锁技术是一种高效的并发控制方法,适用于高并发、大数据量的场景。它通过将数据结构划分为多个段,减小了锁的粒度,提高了并发性能。但是需要注意管理复杂性和空间开销等问题。


✔️HashMap remove方法的优缺点


HashMap的remove方法是一种常用的数据结构操作,其优缺点如下:

优点:

  1. 删除指定键值对:HashMap的remove方法允许用户删除指定的键值对,从而有效地管理数据。
  2. 高效性:在大多数情况下,HashMap的remove方法具有较高的效率,因为它使用哈希表来存储数据。删除操作可以在常数时间内完成。
  3. 线程不安全:HashMap的remove方法不是线程安全的。如果多个线程同时对HashMap进行操作,可能会导致数据不一致的问题。

缺点:

  1. 线程不安全:如上所述,HashMap的remove方法不是线程安全的。如果需要在多线程环境中安全地使用remove方法,需要使用其他同步措施,如使用ConcurrentHashMap。
  2. 数据不一致:由于HashMap的remove方法不是线程安全的,可能会导致数据不一致的问题。例如,在删除一个键值对时,如果其他线程同时修改了该键值对,可能会导致数据不一致。
  3. 依赖哈希函数:HashMap的remove方法依赖于哈希函数来存储和访问数据。如果键的哈希值相同但键不相同,它们将被存储在同一个桶中,导致冲突。这可能会影响删除操作的效率。

HashMap的remove方法具有简单、高效等优点,但也存在线程不安全、数据不一致等缺点。如果需要在多线程环境中安全地使用remove方法,建议使用ConcurrentHashMap等线程安全的集合类。


✔️HashMap的remove方法怎么实现同步


在Java中,HashMap的remove方法不是线程安全的。如果你需要在多线程环境中安全地使用remove方法,可以使用其他线程安全的集合类,如ConcurrentHashMap

然而,如果你仍然想使用HashMap并实现同步,可以使用synchronized关键字对 remove 方法进行同步。这将确保一次只有一个线程可以执行remove方法。以下是一个示例:

public class SynchronizedHashMap {
    private final HashMap<String, String> map = new HashMap<>();

    public synchronized void remove(String key) {
        map.remove(key);
    }
}

示例中,创建了一个名为 SynchronizedHashMap 的类,它包含一个HashMap成员变量map。然后,我们为remove方法添加了synchronized关键字,以确保在多线程环境中该方法的安全性。

注意:使用synchronized关键字对整个remove方法进行同步可能会导致性能下降,因为一次只有一个线程可以执行该方法。如果需要更高的并发性能,建议使用ConcurrentHashMap等线程安全的集合类。


✔️源码解读


public V remove(Object key) {
	Node<k,V> e;
	return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value;
}

还是像前面的老习惯,重点还是来看下 removeNode 方法:


/**
* Implements Map.remove and related methods
* @param hash        hash 值
* @param key         key 值
* @param value       value 值
* @param matchValue  是否需要值匹配 false 表示不需要
* @param movable     不用管
*  @return the node , or null if none
*/
final Node<k, V> removelode(int hash, Object key, Object value, boolean matchValue, boolean movable) {
	//当前HashMap 中的散列表的引用
	Node<KV>[] tab;
	//p: 表示当前的Node元素
	Node<k,V> p;
	// n: table 的长度
	// index: 桶的下标位置
	int n, index;
	//(tab = table) != nul & (n = tab.length) >0 条件成立,说明table不为空 (table 为空就没必要执行了)
	// p = tabrindex = (n - 1) & hash]) != null 将定位到的捅位的元素赋值给 p 并判断定位到的元素不为空
	if ((tab = table) != null && (n = tab,length) > 0 && (p = tabindex = (n - 1) & hashl) != null) {
		//进到 if 里面来了,说明已经定位到元素了
		//node:保存查找到的结果
		//e: 表示当前元素的下一个元素
		Node<k,V> node = nul1, e;
		K k;
		V v;
		//该条件如果成立,说明当前的元素就是要找的结果(这是最简单的情况,这个是很好理解的)
		if (p.hash == hash && ((k = p.key) == key  (key != null && key.equals(k))))  {
			node = p;
		}
		//到这一步,如果 (e = p.next) != null 说明该捅位找到的元素可能是链表或者是树,需要继续判断
		else if ((e = p.next) != null) {
			//树,不考虑
			if (p instanceof TreeNode) {
				node = ((TreeNode<KV>) p).getTreeNode(hash, key);
			}//处理链表的情说
			else {
				do {
					//如果条件成立,说明已经匹配到了元素,直接将查找到的元素赋值给 node,并跳出循环(总体还是很好理解的)
					if (e.hash == hash && ((k = e.key) == key (key != null && key.eguals(k)))) {
						node = e;
						break:
					}
					//将正在遍历的当前的临时元素 e 赋值给 P
					p = e ;
				} while ((e = e.next) != null);
			}
		}
		// node != null 说明匹配到了元素
		//matchValue为false ,所以!matchValue = true,后面的条件直接不用看了
		if (node != null && (!matchValue  (v = node.value) == value  (value != null && value.equals(v)))) {
			//树,不考虑
			if (node instanceof TreeNode) {
				((TreeNode<k,V>) node) .removeTreeNode(this,tab,movable);
			}
			//这种情况是上面的最简单的情况
			else if (node == p) {
				//直接将当前节点的下一个节点放在当前的桶位置《注意不是下一个桶位置,是该桶位置的下一个节点)
				tab[index] = node.next;
			} else {
				//说明定位到的元素不是该桶位置的头元素了,那直接进行一个简单的链表的操作即可
				p.next = node.next ;
			}
			//移除和添加都属于结构的修改,需要同步自增 modCount 的值
			++modCount;
			
			//table 中的元素个数减 1

			--size;
			//啥也没做,不用管
			afterNodeRemoval(node);
			//返回被移除的节点元素
			return node;
		}
	}
	//没有匹配到返回null 即可
	return null:
}

我想对你们说的话,都写在注释里面咯,宝子们一定要好好看哦!

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

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

相关文章

行为型设计模式——模板方法模式

学习难度&#xff1a;⭐ &#xff0c;比较常用 模板方法模式 在面向对象程序设计过程中&#xff0c;程序员常常会遇到这种情况&#xff1a;设计一个系统时知道了算法所需的关键步骤&#xff0c;而且确定了这些步骤的执行顺序&#xff0c;但某些步骤的具体实现还未知&#xff0…

前端面试题集合七(ES6、ES7、ES8、ES9、ES10、ES11、ES12)

ES6&#xff08;2015&#xff09; 1. 类&#xff08;class&#xff09; class Man {constructor(name) {this.name 小豪;}console() {console.log(this.name);} } const man new Man(小豪); man.console(); // 小豪 2. 模块化(ES Module) // 模块 A 导出一个方法 export …

@FunctionalSpringBootTest 和@SpringBootTest注解的区别

FunctionalSpringBootTest 和 SpringBootTest 是Spring框架中用于测试的两个不同注解。下面是它们之间的主要区别&#xff1a; 用途和范围&#xff1a; SpringBootTest&#xff1a;这个注解用于需要测试Spring应用程序上下文的场合。它会加载完整的应用程序上下文&#xff0c;适…

AI教我学编程之C#入门程序详解与拓展

与AI肩并肩 前言一、一个简单的C#程序补充说明对话AI 二、标识符三、关键字四、Main五、空白1. 缩进2. 代码块的间距3. 操作符的空格4. 换行5. 一致性 六、语句七、从程序输出文本主题&#xff1a;从程序中输出文本1. Write 和 WriteLine 方法2. 格式字符串3. 多重标记和值4. 格…

阿里云国际服务器设置安全防护程序

阿里云云服务器&#xff08;ECS&#xff09;提供弹性、安全、高性能、高性价比的虚拟云服务器&#xff0c;满足您的所有需求。立即在这里免费注册&#xff01; 常见 Web 应用程序 请勿对 Web 服务控制台&#xff08;如 WDCP、TOMCAT、Apache、Nginx、Jekins、PHPMyAdmin、Web…

浅谈有源滤波在某棉纺企业低压配电室节能应用

叶根胜 安科瑞电气股份有限公司 上海嘉定 201801 0引言 在电力系统中&#xff0c;谐波的根本原因是非线性负载。由于电子设备、变频器、整流器等。在棉纺企业的大部分设备中被广泛使用&#xff0c;因此会产生大量的谐波电流。我公司的环锭纱线和筒车间的配电设备受到谐波的影…

【C语言】time.h——主要函数介绍(附有几个小项目)

time.h是C标准函数库中获取时间与日期、对时间与日期数据操作及格式化的头文件。返回值类型 size_t&#xff1a;适合保存sizeof的结果&#xff0c;类型为unsigned int&#xff08;%u&#xff09;clock_t&#xff1a;适合存储处理器时间的类型&#xff0c;一般为unsigned long&…

day 43动态规划(5)

day 43 代码随想录 2024.1.10 发烧中。。。简单过一遍等二刷DP问题&#xff01;&#xff08;最近赶一篇paper&#xff01;&#xff09; 1. 1049最后一块石头的重量 dp[j]表示容量&#xff08;这里说容量更形象&#xff0c;其实就是重量&#xff09;为j的背包&#xff0c;最多…

51单片机介绍

1 单片机简介 单片机&#xff0c;英文Micro Controller Unit&#xff0c;简称MCU 内部集成了CPU、RAM、ROM、定时器、中断系统、通讯接口等一系列电脑的常用硬件功能 单片机的任务是信息采集&#xff08;依靠传感器&#xff09;、处理&#xff08;依靠CPU&#xff09;和硬件设…

基于JavaWeb+BS架构+SpringBoot+Vue校园一卡通系统的设计和实现

基于JavaWebBS架构SpringBootVue校园一卡通系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 第一章 概述 4 1.1 研究背景 4 1.2研究目的及意义 4 1.3国内外发展现状 4 1…

DePIN:重塑物理资源网络的未来

点击查看TechubNews更多相关推荐 一、DePIN&#xff1a;物理资源的新整合方式 Depin赛道的项目如雨后春笋般涌现&#xff0c;为市场注入了新的活力。作为先行者&#xff0c;Coinmanlabs已经深入布局Depin赛道&#xff0c;其中最引人注目的项目当属Grass。 什么是DePIN DePIN…

Java项目:114SSM图书管理系统

博主主页&#xff1a;Java旅途 简介&#xff1a;分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 图书管理系统基于SpringSpringMVCMybatis开发&#xff0c;系统主要实现了图书馆借书还书功能&#xff0c;系统分为管理员和读者两种角色。 管理员功能如下…

A股风格因子看板 (2024.01 第4期)

该因子看板跟踪A股风格因子&#xff0c;该因子主要解释沪深两市的市场收益、刻画市场风格趋势的系列风格因子&#xff0c;用以分析市场风格切换、组合风格暴 露等。 今日为该因子跟踪第4期&#xff0c;指数组合数据截止日2024-12-01&#xff0c;要点如下 近1年A股风格因子检验统…

Linux内存管理:(七)页面回收机制

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 1. 触发页面回收 Linux内核中触发页…

TS 36.213 V12.0.0-PUCCH过程

​本文的内容主要涉及TS 36.213&#xff0c;版本是C00&#xff0c;也就是V12.0.0。

2024 Midjourney 基础教程(⼆):了解 Midjourney Bot 和AI绘画使用技巧进阶教学

在上⼀篇⽂章中&#xff0c;我们学到了如何注册 Midjourney &#xff0c;开通付费订阅&#xff0c;并画出了可能是⾃⼰的第⼀张 AI绘画。怎么样&#xff1f;这种将想象的画⾯&#xff0c;变为现实世界图⽚的感觉。 是否有种造物者的错觉&#xff0c;同时有种开盲盒的惊喜感&…

javaWebssh校园物业管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh校园物业管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用 B/S模式开发。开发环境为TOMCAT7.…

2024年天津财经大学珠江学院专升本专业考试准考证打印及考试安排

天津财经大学珠江学院关于2024年高职升本科专业课考试准考证打印等事宜的通知 天津财经大学珠江学院2024年高职升本科专业课考试将于2024年1月14日举行&#xff0c;为确保考试顺利进行&#xff0c;在此提醒各位考生&#xff0c;请务必认真阅读并严格遵守以下事项。 一、考试地…

代码随想录刷题题Day29

刷题的第二十九天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day29 任务 ● 01背包问题&#xff0c;你该了解这些&#xff01; ● 01背包问题&#xff0c;你该了解这些&#xff01; 滚动数组 …

AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(五)—— 项目-新闻头条-数据管理平台-ajax综合案例前端

愿许秋风知我意&#xff0c;解我心中意难平。 项目介绍 项目准备 推荐使用&#xff0c; 每个程序员都有自己的管理方式。 验证码登录 HTML结构&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><met…