Java小白一文讲清Java中集合相关的知识点(八)

news2024/9/25 1:23:44

HashMap底层机制及源码剖析

在这里插入图片描述

  • HashMap底层维护了Node类型的数组table,默认为null

  • 当创建对象时,将加载因子初始化为0.75;

  • 当添加key-value时,通过key的哈希值得到在table的索引,然后判断该索引处是否有元素,如果没有元素直接添加,如果该索引处有

    元素,继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理,如果添加时发现容量不够,则需要扩容 resize();

  • 第一次添加,则需要扩容table容量为16,临界值threshold为12

  • 以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,即24,依次类推;

  • 在Java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>= MIN_TREEIFY_CAPACITY(默认是64),就会进行树化(红黑树);

HashMap源码解读

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            //如果table的索引位置的key的hash和新的key的hash值相同,并
            //满足(table 现有的结点的key和准备添加的key是同一个对象  || equals返回真,就认为不能加入新的k-v)
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            //如果当前的table的已有的Node是红黑树,就按照红黑树的方式来处理
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                //如果找到的结点,后面是链表,就循环比较
                for (int binCount = 0; ; ++binCount) {//死循环
                    if ((e = p.next) == null) {//走到最后了,还没找到与之相同的 
                        //加到链表的屁股后面
                        p.next = newNode(hash, key, value, null);
                        //判断是不是链表中加满了八个
                        if (binCount >= TREEIFY_THRESHOLD - 1) //>= (8-1=7)
                            //树化,当然这里不是立即树化哈,深挖进去,会发现还要满足table的长度>=64
                            //才会树化,反之不符合条件就选择扩容,不急着树化
                            treeifyBin(tab, hash);
                        //我找了一圈,发现没有找到和我一样的,就把我加到屁股后面,然后退出
                        break;
                    }
                    //循环比较的过程中,我发现有一个是相同的,即hash值也相同||值相同,我就退出
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;//替换找到的重复key对应的value
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;//每成功增加一个,就++
        if (++size > threshold)//12--24--48,一旦发现到了threshold临界值,就进入分支开始扩容
            resize();
        afterNodeInsertion(evict);
        return null;
    }




//树化部分的源码
    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        //如果table暂时为null,或者大小还没有到 64,暂时不树化,而是进行扩容
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if (
            .......
        }
    }

HashTable

  • 存放的元素是键值对: 即 k-v
  • hashtable的键和值都不能为null,否则会抛出空指针异常
  • hashTable使用方法基本上和HashMap一样
  • hashTable是线程安全的(因为有synchronized修饰),hashMap是线程不安全的
  • 底层源码剖析
//简单说明一下HashTable的底层
/**
1.底层有数组Hashtable$Entry[]  初始化大小为11
2.临界值 threshold 为 8--> 11*0.75;
3.扩容:按照自己的扩容机制来进行
4.By  执行 addEntry(hash, key, value, index);
	添加K-V ,将其封装到Entry中去
5.当if (count >= threshold) 满足时,就进行扩容
6.按照int newCapacity = (oldCapacity << 1) + 1; 的大小扩容
*/

public synchronized V put(K key, V value) {
    if (value == null) {
            throw new NullPointerException();
        }
    // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];
        for(; entry != null ; entry = entry.next) {
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;
                entry.value = value;
                return old;
            }
        }
//hashtable的底层是entry数组,通过以下的add方法将key、value放进entry中,然后添加到数组中去
        addEntry(hash, key, value, index);
        return null;
    }

}


//addEntry方法底层
    private void addEntry(int hash, K key, V value, int index) {
        modCount++;

        Entry<?,?> tab[] = table;
        //当存放的元素数量大于临界值
        if (count >= threshold) {
           //进入这个方法
            rehash();

            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>) tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        count++;
    }


//rehash()底层源码
    @SuppressWarnings("unchecked")
    protected void rehash() {
        //oldCapacity起初为11嘛
        int oldCapacity = table.length;
        Entry<?,?>[] oldMap = table;

        // 扩容后新的容量=oldCapacity乘以2,再+1;
        //这就是起初容量为11,之后扩容后变为11*2+1=23的原因
        int newCapacity = (oldCapacity << 1) + 1;
        //如果新容量-数组最大值2147483639仍然大于0,则进入分支
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

        modCount++;
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        table = newMap;

        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                old = old.next;

                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;
            }
        }
    }

HashMap和HashTable之间的对比

线程安全(同步)效率允许null键 null值
HashMap不安全可以
HashTable安全较低不可以

Properities

  • Properities类继承自HashTable类并且实现了Map接口,也是使用了一种键值对的形式来保存数据
  • 它的使用特点和HashTable类似
  • Properities还可以用于从xxx.properities文件中,加载数据到Properties类对象,并进行读取和修改
  • 说明:工作后,xxxx.properities文件通常作为配置文件,这个知识点在IO流举例;

TreeSet

  • 自动排序,TreeSet中的元素会自动按照自然顺序,例如数字从小到大,字母按照字典顺序,或者通过自定义的比较器排列;
  • 不允许重复元素,TreeSet会检查插入的元素是否已经存在,如果存在相同的元素,新的元素将不会被添加
      public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的
        treeSet.add("jason");
        treeSet.add("R");
        treeSet.add("K");
        treeSet.add("AAA");

        System.out.println(treeSet);
        //[AAA, K, R, jason]

        //2.我希望添加的元素,可以按照字符串大小来排序
        //3.我们可以使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //  并指定排序规则
        TreeSet treeSetNB = new TreeSet(new Comparator() {

//源码解读,当传给TreeSet一个比较器时,深挖底层,我们会发现其将传入的比较器对象 赋给了TreeSet底层的
//TreeMap的属性this.comparator,也就是将匿名对象,传给了底层TreeMap的comparator属性
            /**
	public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }*/
//在调用treeSet.add("AAA")时,在底层会执行到
            /**
            //此中的cpr就是我们的匿名内部类(对象)
            	Comparator<? super K> cpr = comparator;
                    if (cpr != null) {
                        do {
                            parent = t;
                            //动态绑定到我们的匿名内部类(对象) compare
                            cmp = cpr.compare(key, t.key);
                            if (cmp < 0)
                                t = t.left;
                            else if (cmp > 0)
                                t = t.right;
                                //如果相等,即返回0,那么这个key就没有加入
                            else
                                return t.setValue(value);
                        } while (t != null);
       		    }
            */
            @Override
            public int compare(Object o1, Object o2) {
                //这里的这句话调用字符串的compareTo方法,默认按照字符串来比较大小
                //这里实现从大到小的比较规则
                return ((String)o2).compareTo((String)o1);
            }
        });
        treeSetNB.add("jason");
        treeSetNB.add("K");
        treeSetNB.add("R");
        treeSetNB.add("AAA");

        System.out.println("添加了比较器后的treeSet:"+treeSetNB);



    }



TreeMap

  • 键的排序:TreeMap按照键的自然顺序,例如数字从小到大,字母按字典顺序,或者根据提供的Comparator 进行排序;

    ​ 因此,插入元素时会自动排序,而不是按照插入的顺序存储;

  • 不允许null键:TreeMap不允许null作为键,这与HashMap允许一个nulll键不同,但是TreeMap允许null值,可以有多个null值;

    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap();
        treeMap.put("1",null);
        treeMap.put("2",null);
        System.out.println(treeMap);
        //{1=null, 2=null}
    }

Collection工具类

  • Collection是一个操作Set、List和Map等集合的工具类
  • Collection中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作
  • 排序操作
  • reverse(List):反转List中元素的顺序
  • shuffle(List):对List集合元素进行随机排序
  • sort(List):根据元素的自然顺序对指定List集合元素按升序排序
  • sort(List,Comparator):根据指定的Comparator 产生的顺序对List 集合元素进行排序
  • swap(List,int,int):将指定List集合中的 i 处元素和 j 处元素进行交换
    public static void main(String[] args) {
        //创建ArrayList 集合,用于测试。
        ArrayList list = new ArrayList();
        list.add("kerwin");
        list.add("h活在当下hhh");
        list.add("AA感受每一段旅程");
        list.add("moment");

        System.out.println(list);
        //[kerwin, h活在当下hhh, AA感受每一段旅程, moment]

        //reverse 反转
        Collections.reverse(list);
        System.out.println(list);
        //[moment, AA感受每一段旅程, h活在当下hhh, kerwin]

        //shuffle  随机排序
        Collections.shuffle(list);
        System.out.println(list);
        //[h活在当下hhh, AA感受每一段旅程, kerwin, moment]

        //sort  根据元素的自然顺序对指定的List集合元素按升序排序
        Collections.sort(list);
        System.out.println(list);
        //[AA感受每一段旅程, h活在当下hhh, kerwin, moment]

        //sort(list , Comparator) 传入比较器进行排序
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                String str1 = (String)o1;
                String str2 = (String)o2;
                return str2.compareToIgnoreCase(str1);
            }
        });
        System.out.println(list);
        //[moment, kerwin, h活在当下hhh, AA感受每一段旅程]

        //swap  将指定List集合中的i 处元素和 j 处元素进行交换;
        Collections.swap(list,0,1);b `	1N2QWA
        System.out.println(list);
        //[kerwin, moment, h活在当下hhh, AA感受每一段旅程]
    }

  • 查找、替换
  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  • Object max(Collection ,Comparator):根据Comparator指定的顺序返回给定集合中的最大元素
  • Object min(Collection)
  • Object max(Collection,Comparator)
  • int frequency(Collection ,Object):返回指定集合中指定元素的出现次数
  • void copy(List dest, List src):将src 中的内容复制到dest中
  • boolean replaceAll(List list ,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
    public static void main(String[] args) {
        //创建ArrayList 集合,用于测试。
        ArrayList list = new ArrayList();
        list.add("kerwin");
        list.add("hhhh");
        list.add("AAjourney");
        list.add("moment");

        System.out.println(list);
        //[kerwin, hhhh, AAjourney, moment]


        //Object max(Collection);  返回给定集合中的最大元素
        System.out.println("自然顺序下的最大元素");
        System.out.println(Collections.max(list));
        //moment

        //自定义比较器,然后返回自定义规则下的最大元素
        //比如,我要返回长度最大的元素
        Object maxObject = Collections.max(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                String str1 = (String)o1;
                String str2 = (String)o2;

                return str1.length()-str2.length();
                /**
                 * return ((String)o1).length()-((String)o2).length();
                 */
            }
        });
        System.out.println("自定义比较器下的最长元素");
        System.out.println(maxObject);
        //AAjourney

        //min(Collection)
        System.out.println("自然顺序下的最小元素:");
        System.out.println(Collections.min(list));
        //AAjourney


        //同样,实现自定义比较器,然后返回长度最小的元素
        Object minObject = Collections.min(list, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                /**
                 * 这里想补充一点容易犯错的点:你要像下面这样写的时候,务必要留意括号的位置,
                 * ((String)o1)  这个对应的才是String,才会有length()API可以调用
                 * 如果不留意这一点,就会频频报错hhh
                 *
                 */
                return ((String) o1).length() - ((String) o2).length();
            }
        });
        System.out.println("自定义比较器下的最短元素");
        System.out.println(minObject);
        //hhhh

        //  int  frequency(Collection Object) 返回指定集合中指定元素出现的次数
        list.add("hhhh");
        System.out.println(list);
        //[kerwin, hhhh, AAjourney, moment, hhhh]

        int hhhhFre = Collections.frequency(list, "hhhh");
        System.out.println(hhhhFre);
        //2  即"hhhh"这个对象在集合中出现了2次

        //void copy(List dest,List src)
        ArrayList testList = new ArrayList();
        testList.add("Bingo");
        testList.add("Bingo");
        //将testList集合中的元素,复制到list中去
        Collections.copy(list,testList);
        System.out.println(testList);
        //[Bingo, Bingo]

        System.out.println(list);
        //[Bingo, Bingo, AAjourney, moment, hhhh]


        //boolean replaceAll(List list, Object oldVal, Object newVal)
        Collections.replaceAll(list,"hhhh","hhhhhDamn");
        System.out.println(list);
        //[Bingo, Bingo, AAjourney, moment, hhhhhDamn]


    }
	

拓展:比较器专题练习

      public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("apple");
        list.add("banana");
        list.add("cherry");
        list.add("kiwi");

        //1.按照字符串的长度来 进行从短到长排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        });
        System.out.println("按照字符串长度,由短到长排序如下:");
        System.out.println(list);
        //[kiwi, apple, banana, cherry]

        //2.按照字符串的最后一个字符从大到小排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                /**
                 * 这样也行!!!
                 *  char lastChar1 = o1.charAt(o1.length() - 1);
                    char lastChar2 = o2.charAt(o2.length() - 1);
                    return Character.compare(lastChar2, lastChar1);  // 从大到小排序
                 */
                return o2.charAt(o2.length()-1)-o1.charAt(o1.length()-1);
            }
        });
        System.out.println("按照字符串的最后一个字符从大到小排序:");
        for(String obj : list){
            System.out.print(obj+"\t");
        }
        //cherry	kiwi	apple	banana

        //3.按字符串中的元音字母数量从多到少排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return countVowels(o2) - countVowels(o1);  // 从多到少排序
            }
            private int countVowels(String str) {
                int count = 0;
                for (char c : str.toLowerCase().toCharArray()) {
                    if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
                        count++;
                    }
                }
                return count;
            }
        });
        System.out.println();
        System.out.println("按字符串中的元音字母数量从多到少排序,如下:");
        System.out.println(list);
        //[banana, kiwi, apple, cherry]

        //4.按字符串字母逆序排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.toCharArray()[0]-o1.toCharArray()[0];
            }
        });
        System.out.println("按字符串字母逆序排序");
        System.out.println(list);
        //[kiwi, cherry, banana, apple]

        //5.按字符串是否以元音字母开头排序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                boolean startsWithVowel1 = startsWithVowel(o1);
                boolean startsWithVowel2 = startsWithVowel(o2);

                if (startsWithVowel1 && !startsWithVowel2) {
                    return -1;
                } else if (!startsWithVowel1 && startsWithVowel2) {
                    return 1;
                } else {
                    return o1.compareTo(o2);  // 如果开头情况相同,则按字母顺序排序
                }
            }

            private boolean startsWithVowel(String str) {
                char firstChar = Character.toLowerCase(str.charAt(0));
                return firstChar == 'a' || firstChar == 'e' || firstChar == 'i' || firstChar == 'o' || firstChar == 'u';
            }
        });
        System.out.println("按字符串是否以元音字母开头排序");
        System.out.println(list);
        //[apple, banana, cherry, kiwi]

    }

//输出结果如下:
按照字符串长度,由短到长排序如下:
[kiwi, apple, banana, cherry]
按照字符串的最后一个字符从大到小排序:
cherry	kiwi	apple	banana	
按字符串中的元音字母数量从多到少排序,如下:
[banana, kiwi, apple, cherry]
按字符串字母逆序排序
[kiwi, cherry, banana, apple]
按字符串是否以元音字母开头排序
[apple, banana, cherry, kiwi]

集合总结

开发中如何选择集合实现类

  • 先判断存储的类型(一组对象或一组键值对)
  • 一组对象(单列数据):Collection接口
    • 允许重复:List
      • 增删多:LinkedList[底层维护了一个双向链表]
      • 改查多:ArrayList[底层维护了Object 类型的可变数组]
    • 不允许重复:Set
      • 无序:HashSet [底层是HashMap,维护了一个哈希表,即数组+链表+红黑树]
      • 排序:TreeSet
      • 插入和取出顺序一致:LinkedHashSet 维护数组+ 双向链表
  • 一组键值对(双列):Map
    • 键无序:HashMap [ 底层是:哈希表 jdk7:数组+链表 jdk8:数组+链表+红黑树 ]
    • 键排序:TreeMap
    • 键插入和取出顺序一致:LinkedHashMap
    • 读取文件:Properties

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

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

相关文章

力扣 — — 2555. 两个线段获得的最多奖品

力扣 — — 2555. 两个线段获得的最多奖品 一、题目描述 题目大意&#xff1a;给定一个数组prizePositions&#xff0c;数组中的值表示的是奖品的位置&#xff0c;每一个位置可以有多个奖品&#xff0c;并且设定一个线段的长度 K K K&#xff0c;要求从所有奖品位置中选择两个…

修改Netty 中EventLoopGroup的线程名字前缀

此方案针对 netty 4 , 阅读Netty 源码的过程中涉及到多种线程跳转&#xff0c;2-1 3-1 4-1 类似的命名头晕眼花&#xff0c;直接改了成方便辨认的名字吧&#xff01; 代码如下&#xff1a; public static EventLoopGroup getEventLoopGroup(String name, int nThread) {Defaul…

第十一周:机器学习

第十一周周报 摘要Abstract机器学习1. 注意力机制&#xff08;下&#xff09;1.1 multi-head self-attention&#xff08;多头注意力机制&#xff09;1.2 Positional Encoding&#xff08;位置编码&#xff09;1.3 truncated self attention&#xff08;截断式注意力机制&#…

SVGJS使用

svgjs用于操作 SVG 和动画的轻量级库。 官网 SVG.js v3.2 |家 (svgjs.dev) 1、安装 npm install svgdotjs/svg.js 或者下载直接引用 2、使用 <script src"https://cdn.jsdelivr.net/npm/svgdotjs/svg.js3.0/dist/svg.min.js"></script> import { S…

Win11 22H2/23H2用户速来!9月更新补丁KB5043076已发布

系统之家于9月11日发出最新报道&#xff0c;微软针对Win11用户发布了9月最新的更新补丁KB5043076&#xff0c;22H2用户升级系统后&#xff0c;版本号升至22621.4169&#xff0c;23H2用户的系统版本也升至22631.4169。此次更新支持用户从Windows分享窗口将内容共享到安卓设备。以…

95. UE5 GAS RPG 实现创建多段飞弹攻击敌人

从这篇开始&#xff0c;我们将实现一些技能&#xff0c;比如多段火球术&#xff0c;闪电链等等。 在这一篇里&#xff0c;我们先实现多段火球术&#xff0c;技能可以通过配置发射出多个火球术进行攻击。 创建多段火球函数 首先在我们之前创建的RPGFireBolt.h类里面增加一个生…

k8s的环境配置

一、前期系统环境准备 准备3台主机&#xff1a;硬盘50G cpu2个 内存2G 1、3台主机同时配置 1&#xff09;关闭防火墙与selinux、NetworkManager [rootk8s-master ~]# systemctl stop firewalld[rootk8s-master ~]# systemctl disable firewalldRemoved symlink /etc/systemd/…

ctfshow-web入门-sql注入-web248-UDF 注入

udf 全称为&#xff1a;user defined function&#xff0c;意为用户自定义函数&#xff1b;用户可以添加自定义的新函数到 Mysql 中&#xff0c;以达到功能的扩充&#xff0c;调用方式与一般系统自带的函数相同&#xff0c;例如 contact()&#xff0c;user()&#xff0c;versio…

VUE实现刻度尺进度条

一、如下图所示效果: 运行后入下图所示效果: 实现原理是用div画图并动态改变进度, 二、div源码 <div style="width: 100%;"><div class="sdg_title" style="height: 35px;"><!--对话组[{{ dialogGroup.index }}]编辑-->&…

如何在微信中使用AI智能回复,真AI大模型;微加机器人免费智能回复功能

之前一直想实现在微信中使用AI大模型进行消息回复&#xff0c;也使用过很多开源的工具自己调OpenAI的API&#xff0c;但是整体太复杂&#xff0c;而且跑在自己电脑上也不稳定 今天发现微加机器人也支持AI回复&#xff0c;而且AI功能还是免费的&#xff0c;没有tokens收费 微加…

【Gephi】可视化教程

此教程专供欣欣向荣及其舍友使用 文章目录 导入数据上色改变布局设置节点大小统计拓扑结构输出图形保存文件 导入数据 点击【文件】-【导入电子表格】 先选择csv格式的network 直接下一步 点击完成 【图的类型】改为“有向的” 点击确认 会弹出报错&#xff0c;直接clos…

CSS 响应式设计(补充)——WEB开发系列36

随着移动设备的普及&#xff0c;网页设计的焦点逐渐转向了响应式设计。响应式设计不仅要求网页在各种屏幕尺寸上良好展示&#xff0c;还要适应不同设备的特性。 一、响应式设计之前的灵活布局 在响应式设计流行之前&#xff0c;网页布局通常是固定的或流动的。固定布局使用固定…

vc-upload源码分析 -- ant-design-vue系列

vc-upload源码分析 – ant-design-vue系列 1 整体结构 上传组件的使用分两种&#xff1a;点击上传和拖拽上传。 点击的是组件或者是卡片&#xff0c;这个是用户通过插槽传递的。除上传外的其他功能&#xff0c;比如预览、自定义文件渲染等功能&#xff0c;也不是上传的核心功…

2. 变量和指令(omron 机器自动化控制器)——1

机器自动化控制器——第二章 变量和指令 1 2-1 变量一览表MC通用变量轴变量▶ 轴组变量 运动控制指令的输入变量输入变量的有效范围▶ 枚举体一览表 运动控制指令的输出变量运动控制指令的输入输出变量 2-1 变量一览表 MC功能模块使用的变量分为两类。 一类是监视轴等的状态及…

【SQL】百题计划:SQL对于空值的比较判断。

[SQL]百题计划 方法&#xff1a; 使用 <> (!) 和 IS NULL [Accepted] 想法 有的人也许会非常直观地想到如下解法。 SELECT name FROM customer WHERE referee_Id <> 2;然而&#xff0c;这个查询只会返回一个结果&#xff1a;Zach&#xff0c;尽管事实上有 4 个…

关于使用HAWQ量化框架执行训练前推理的性能崩溃问题

问题描述 今天debug量化模型遇到一个比较奇怪的问题&#xff0c;之前从来没有注意过&#xff1a; 现在量化模型的流程是&#xff1a; 1&#xff09;加载预训练好的浮点数权重模型&#xff1b; 2&#xff09;将模型架构替换成量化架构&#xff08;逐模块替换&#xff09;&#…

Linux和C语言(Day11)

一、学习内容 讲解有参函数 形参 和 实参 形参——定义时的参数&#xff0c;形式上的参数&#xff0c;没有实际意义&#xff0c;语法上必须带有数据类型 void fun(int a,int b); void fun(int a[],int n); void fun(char *s); 可以是&#xff1a;变量、数组、指针 实参——调用…

【笔记】物理化学绪论

文章目录 1. 物理化学的目的和研究内容什么是物理化学&#xff1f;目的内容 2. 物理化学的学习方法3. 物理量的表示和运算&#xff08;1&#xff09;物理量的表示&#xff08;2&#xff09;量值计算 4. 课程安排 1. 物理化学的目的和研究内容 用物理变化 P、V、T热效应电效应…

【数据结构】排序算法系列——序言(附源码+图解)

作为基础算法的中流砥柱部分&#xff0c;排序算法一直都是计算机学习者们不可忽略的一部分。而其中的算法思想也蕴含着许多在今后的算法学习甚至是整个计算机技术的学习之中仍然熠熠生辉的算法思想&#xff0c;它们引领着我们不断探索算法的奥秘之处。所以&#xff0c;学习排序…

黑神话悟空大圣残躯怎么打 头目大圣残躯攻略

​面对《黑神话&#xff1a;悟空》中的终极挑战——大圣残躯&#xff0c;掌握其打法要点&#xff0c;是通往胜利的关键。下面&#xff0c;就让我们一步步解析如何战胜这位强大的最终BOSS吧。 一、BOSS位置 随主线流程必解锁。击败石猿后&#xff0c;齐天大圣的真身——大圣残躯…