java -数据结构,List相关基础知识,ArrayList的基本使用,泛型的简单、包装类介绍

news2024/9/20 17:01:35

一、 预备知识-泛型(Generic)

1.1、泛型的引入

比如:我们实现一个简单的顺序表

class MyArrayList{
    public int[] elem;
    public int usedSize;
    public MyArrayList(){
        this.elem = new int[10];
    }
    public void add(int key){
        this.elem[usedSize] = key;
        usedSize++;
    }
    public int getPos(int pos){
        return this.elem[pos];
    }
}

问题:此时我么发现我们实现的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?

在这里插入图片描述

泛型的意义

1、当我们指定数据类型之后,它会在编译器编译的时候,就帮你检查存储的数据类型是否匹配。自动对数据类型进行检查。
2、在我们获取元素的时候,发现数据类型不匹配,此时就会自动的将类型转换成相同类的数据。自动对类型进行强转类型转换。

下面顺序表的写法是不对的,只是为了暂时的用起来

class MyArrayList<E>{
    public E[] elem;
    public int usedSize;
    public MyArrayList(){
        this.elem = (E[])new Object[10];
    }
    public void add(E key){
        this.elem[usedSize] = key;
        usedSize++;
    }
    public E getPos(int pos){
        return  this.elem[pos];
    }
}

面试问题:泛型是怎么编译的?

在这里插入图片描述

1.泛型是编译期的一种机制(擦除机制)。
擦除机制:它会把尖括号这些内容擦除掉,也就说程序运行的时候,就没有这些东西了。所以说程序运行起来,再去获取它的类型是不可能的,因为都被擦掉了。

在这里插入图片描述

然后我们再来看一下细节

在这里插入图片描述

1.2、泛型的总结

  1. 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
  2. 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。
  3. 泛型是一种编译期间的机制,即 MyArrayList< Person > 和 MyArrayList< Book > 在运行期间是一个类型。
  4. 泛型是 java 中的一种合法语法,标志就是尖括号 <>

二、预备知识-包装类(Wrapper Class)

Object 引用可以指向任意类型的对象,但有例外出现了,8 种基本数据类型不是对象,那岂不是刚才的泛型机制要
失效了?
实际上也确实如此,为了解决这个问题,java 引入了一类特殊的类,即这 8 种基本数据类型的包装类,在使用过程
中,会将类似 int 这样的值包装到一个对象中去。

2.1、基本数据类型和包装类直接的对应关系

在这里插入图片描述
基本就是类型的首字母大写,除了 Integer 和 Character

2.2、包装类的使用,装箱(boxing)和拆箱(unboxing)

例如:此时我们将一个字符串类型的数据转换成int类型的数据

public static void main(String[] args) {
        String str = "123";
        int b =  Integer.valueOf(str);
        System.out.println(b + 11);
    }

在这里插入图片描述

什么是装包和拆包

  • 装箱,装包: 就是将基本数据类型的数据转换成包装类类型 的数据
  • 拆箱,拆包:就是将包装类类型的数据转换成基本数据类型的数据

在这里插入图片描述

阿里面试题,和装包和拆包有关

下面执行结果为什么会不相等???

public static void main(String[] args) {
        Integer a = 129;
        Integer b = 129;
        System.out.println("是否相等: " + (a == b));
    }

在这里插入图片描述
为什么???
在这里插入图片描述

三、List的使用

3.1、ArrayList 和 顺序表

List是一个接口,不能实例化,但是可以实例一个就提的对象,也可以通过具体的类来实例具体的对象

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        
        ArrayList<String> arrayList = new ArrayList<>();
    }

下面的这张图是ArrayList实现的接口和继承的抽象类,但是这张图并不具体
在这里插入图片描述
下面这张图才是ArrayList具体实现的接口和类
在这里插入图片描述
【说明】

  1. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  2. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  3. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  4. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  5. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

3.2、ArrayList 的构造方法

在只用java中的类库时,一定要先看一下类库中的构造方法

在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
        //不带参数的构造方法,默认大小为0
        List<String> list1 = new ArrayList<>();
        //带一个参数的构造方法,大小为10
        List<String> list2 = new ArrayList<>(10);
        //将list2作为参数传递,但是list2和list3里面存储的数据类型必须一致
        List<String> list3 = new ArrayList<>(list2);
    }

ArrAyList的三种打印方式

1. 直接打印

public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        list1.add("hello");
        list1.add("word");
        list1.add("!!!");
        System.out.println(list1);
    }

在这里插入图片描述

2. 使用for和for-each循环打印

ArrayList本质上是一个数组,所以可以使用for循环打印,当然也可以使用for-each打印

public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        list1.add("hello");
        list1.add("word");
        list1.add("!!!");
        for (String str : list1) {
            System.out.println(str + " ");
        }
    }

在这里插入图片描述

3. 迭代器打印

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("123");
        list.add("hello");
        list.add("baidu");
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next() + " ");
        }
    }

在这里插入图片描述

4、用于List相关的迭代器打印

List<String> list = new ArrayList<String>();
        list.add("123");
        list.add("hello");
        list.add("baidu");
        ListIterator<String> it = list.listIterator();
        while (it.hasNext()){
            System.out.println(it.next() + " ");
        }

在这里插入图片描述

3.3、ArrayList的常用方法

在这里插入图片描述

3.3.1、boolean add(E e) - 添加元素

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("123");
        list.add("hello");
        list.add("baidu");
        System.out.println(list);
    }

在这里插入图片描述

3.3.2、void add(int index, E element) - 在index位置添加元素E

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("123");
        list.add("hello");
        list.add("baidu");
        list.add(1,"++++");
        System.out.println(list);
    }

在这里插入图片描述

3.3.3、boolean addAll(Collection<? extends E> c) - 尾插对象e(e是和ArrayList一样的对象)

相当于在顺序表后面在插入一个顺序表

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("123");
        list.add("hello");
        list.add("baidu");
        List<String> list1 = new ArrayList<String>();
        list1.add("*****");
        list1.add("888");
        list.addAll(list1);
        System.out.println(list);
    }

在这里插入图片描述

3.3.4、E remove(int index) - 删除index位置的元素

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("123");
        list.add("hello");
        list.add("baidu");
        System.out.println(list);
        list.remove(1);
        System.out.println(list);
    }

在这里插入图片描述

3.3.5、boolean remove(Object o) - 删除第一次遇见的元素

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        boolean b = list.remove("b");
        System.out.println(list);
    }

在这里插入图片描述

3.3.6、E get(int index) - 获取index位置的元素

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        String str = list.get(2);
        System.out.println(str);
        System.out.println(list);
    }

在这里插入图片描述

3.3.7、E set(int index, E element) - 将index位置的元素设置成element

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        String str = list.set(2,"***");
        System.out.println(str);
        System.out.println(list);
    }

在这里插入图片描述

3.3.8、void clear() - 清空ArrayList

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        System.out.println(list);
        list.clear();
        System.out.println(list);
    }

在这里插入图片描述

3.3.9、boolean contains(Object o) - 判断一个元素是否存在

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("c");
        boolean ret = list.contains("b");
        System.out.println(ret);
        System.out.println(list);
    }

在这里插入图片描述

3.3.10、int indexOf(Object o) - 返回第一个o 的下表

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("b");
        list.add("c");
        int ret = list.indexOf("b");
        System.out.println(ret);
        System.out.println(list);
    }

在这里插入图片描述

3.3.11、int lastIndexOf(Object o) - 返回最后一个o 的下表

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("b");
        list.add("b");
        list.add("c");
        int ret = list.lastIndexOf("b");
        System.out.println(ret);
        System.out.println(list);
    }

在这里插入图片描述

3.3.11、List subList(int fromIndex, int toIndex) - 截取部分list

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("A");
        list.add("M");
        list.add("c");
        List<String> sub = list.subList(1,3);
        System.out.println(sub);
    }

在这里插入图片描述

在截取的时候注意使用事项

在这里插入图片描述

四、ArrayList底层的扩容机制

在这里插入图片描述
得出结论:
1、如果ArrayList调用不带参数的构造方法,那么顺序表的大小为0,当第一次 add 的时候,整个数组的大小为10,当这10个放满的时候,开始扩容,以15倍的方式进行扩容。
2、如果调用指定容量大小的构造方法,那顺序表的大小就是指定的容量,如果放满了,还是以1.5倍的方式进行扩容。

五、模拟实现ArrayList

这次的实现就会比上次的更好一点,模拟源代码的实现
在这里插入图片描述
当创建好之后,顺序表里面的操作就按照下面的操作来写
在这里插入图片描述

add

在使用add函数的时候要注意,调用的 时候不带参数的构造方法,还是调用带参数的构造方法,如果满了就要扩容
在这里插入图片描述

public class MyArrayList<E> {
    private Object[] elementData;
    private int size;//代表有效的数据个数
    private static final int DEFAULT_CAPACITY = 10;

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE-8;

    public MyArrayList(){
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public MyArrayList(int capacity) {
        //对参数进行判断
        if(capacity > 0){
            this.elementData = new Object[capacity];
        }else if(capacity == 0){
            this.elementData = new Object[0];
        }else {
            throw new IllegalArgumentException("初始化容量不能为负数");
        }
    }

    /**
     * 添加元素,添加的元素在数组的最后面,尾插
     * @param e
     * @return
     */
    public boolean add(E e){
        //
        ensureCapacityInternal(size+1);
        elementData[size+1] = e;
        size++;
        return true;
    }

    private void ensureCapacityInternal(int minCapacity) {
        //计算出需要的容量
        int capacity = calculateCapacity(elementData,minCapacity);
        //拿着计算的容量,满了扩容,空的分配内存
        ensureExplicitCapacity(capacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? (Integer.MAX_VALUE) : (MAX_ARRAY_SIZE);
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //1、是否之前的elemenData 数组分配内存
        if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
            return Math.max(DEFAULT_CAPACITY,minCapacity);
        }
        //2、分配过就返回+1的值
        return minCapacity;
    }
}

add(int index, E e) - 在指定位置插入元素

在这里插入图片描述

/**
     * 在index位置添加元素
     * @param index
     * @param e
     */
    public void add(int index, E e) {
        //判断index位置是否合法
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        elementData[index] = e;
        size++;
    }

    /**
     * 判断index位置是否合法
     * @param index
     */
    private void rangeCheckForAdd(int index){
        if(index < 0 || index > size){
            throw new IndexOutOfBoundsException("index位置不合法");
        }
    }

remove(object o) - 删除第一次遇到的元素 o

在这里插入图片描述

/**
     * 删除第一次遇见的元素 0
     * @param o
     * @return
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    /**
     * 移动元素
     * @param index
     */
    private void fastRemove(int index) {
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

就简单的实现几个功能

面试题 - CVTE 删除第一个字符串中出现的第二个字符串中的字符

删除第一个字符串中出现的第二个字符串中的字符
例如 :
String str1= “welcome to cvte”
String str2= “come”
输出结果:wl t vte

我们遍历str1 ,看str2的字符是否在str1中,如果不在那就将这个字符放入ArrayList中,如果在那就不放进去

public static void main(String[] args) {
        String str1 = "welcome to cvte";
        String str2 = "come";
        ArrayList<Character> list = new ArrayList<>();

        for (int i = 0; i < str1.length(); i++) {
            char ch = str1.charAt(i);
            if(!str2.contains(ch+"")){
                list.add(ch);
            }
        }
        for (char ch : list) {
            System.out.print(ch);
        }
    }

ArrayList 实践案例 - 扑克牌

目的:
1.构造一副扑克牌
2.揭牌

在这里插入图片描述

class Card{
    private int rank;//数字
    private String suit;//花色

    public Card(String suit, int rank) {
        this.rank = rank;
        this.suit = suit;
    }

    public int getRank() {
        return rank;
    }

    public String getSuit() {
        return suit;
    }

    @Override
    public String toString() {
        return "[ 花色 "+ this.suit +  " " + this.rank + " ]";
    }
}

public class Dome {
    //构造一副牌,这副牌里面没有大小王
    //四个花色
    private static String[] suits = {"♥","♠","♣","♦"};

    private static ArrayList<Card> byCard(){
        ArrayList<Card> cards = new ArrayList<>();

        //每个花色匹配不同的数字,这样就创建好了一副牌
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <=13; j++) {
//                String suit = suits[i];
//                Card card = new Card(suit,j);
//                cards.add(card);
                cards.add(new Card(suits[i],j));
            }
        }
        return cards;
    }

    //牌创建好之后就要洗牌
    private static void shuFfle(ArrayList<Card> cards){
        // 牌数是52,数组下标就是51
        // 从最后一张牌开始,随机与 本身 或者 本身前面的任意一张牌 交换位置。
        // 这样的做交换性 比 从开头洗  的 打乱顺序的 效率 高。
        for (int i = cards.size()-1; i > 0 ; i--) {
            Random random = new Random();
            // 通过 Random的引用 random 去调用 nextInt() 方法。
            // random.nextInt() 方法,根据括号中的值,随机生成 0 ~ 括号中的值
            int rand = random.nextInt(i);
            swap(cards,i,rand);
        }
    }

    private static void swap(ArrayList<Card> cards,int i, int j){
        // 我们现在是面向对象,ArrayList虽然底层是一个数组,但是需要使用方法,才能操作数组的元素
        // 并不能像数组一样,直接操作

        // Card tmp = list[i];
        Card tmp = cards.get(i);// 获取 顺序表中,对应下标的元素

        // list[i] = list[j];
        cards.set(i,cards.get(j));// 将 j下标的元素,赋给 i 下标的元素,

        // list[j] = tmp;
        cards.set(j,tmp);

    }

    public static void main(String[] args) {
        ArrayList<Card> car = byCard();//创建牌
        System.out.println(car);
        shuFfle(car);//洗牌
        System.out.println(car);

        System.out.println("三个人轮流揭牌5张牌");

        ArrayList<ArrayList<Card>> hand = new ArrayList<>();

        ArrayList<Card> hand1 = new ArrayList<>();
        ArrayList<Card> hand2 = new ArrayList<>();
        ArrayList<Card> hand3 = new ArrayList<>();

        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);

        //每个人轮流揭牌
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                Card card = car.remove(0);
                hand.get(j).add(card);
            }
        }
        System.out.println("第一个人的牌:" + hand1);
        System.out.println("第二个人的牌:" + hand2);
        System.out.println("第三个人的牌:" + hand3);

        System.out.println("剩下的牌:" + car);
    }
}

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

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

相关文章

Ethercat系列(4)Twcat3激活配置过程的协议分析

广播设置ESC的4个端口环路设置从-》主广播读从站状态机实际状态主-》从从-》主广播清除接收错误计数器0x300且读应用层状态从-》主顺序读从站基本信息&#xff0c;链路层配置与状态从-》主广播读从站状态机状态主-》从从-》主顺序写ESC控制模式&#xff0c;广播读从站状态主-》…

一、图机器学习导论【CS224W】(Datawhale组队学习)

开源内容&#xff1a;https://github.com/TommyZihao/zihao_course/tree/main/CS224W 子豪兄B 站视频&#xff1a;https://space.bilibili.com/1900783/channel/collectiondetail?sid915098 斯坦福官方课程主页&#xff1a;https://web.stanford.edu/class/cs224w 文章目录前…

C++中的标准输入和输出

一、 C 输入输出的含义 在C语言中我们的输入和输出都是以printf和scanf进行操作的。他们都是函数。在C中的我们的输入输出都是以终端为对象的&#xff0c;即从键盘输入数据&#xff0c;运行结果输出到显示器屏幕上。从操作系统(Linux)的角度看&#xff0c;每一个与主机相连的输…

RKE2部署高可用Rancher v2.7.1

先决条件 注意修改主机名&#xff0c;不要有冲突 第一个server节点安装 官方文档的描述感觉对于新手来说太不友好了&#xff0c;建议以下链接都看一下。Rancher新老文档都建议看一下&#xff0c;不然刚刚入门很蒙。 RKE2快速开始&#xff1a;https://docs.rke2.io/zh/install…

html+css综合练习一

文章目录一、小米注册页面1、要求2、案例图3、实现效果3.1、index.html3.2、style.css二、下午茶页面1、要求2、案例图3、index.html4、style.css三、法国巴黎页面1、要求2、案例图3、index.html4、style.css一、小米注册页面 1、要求 阅读下列说明、效果图&#xff0c;进行静…

由浅入深,聊聊OkHttp的那些事(很长,很细节)

引言 在 Android 开发的世界中&#xff0c;有一些组件&#xff0c;无论应用层技术再怎么迭代&#xff0c;作为基础支持&#xff0c;它们依然在那里。 比如当我们提到网络库时&#xff0c;总会下意识想到一个名字&#xff0c;即 OkHttp 。 尽管对于大多数开发者而言&#xff0…

spark02-内存数据分区分配原理

代码&#xff1a;val conf: SparkConf new SparkConf().setMaster("local[*]").setAppName("wordcount") val scnew SparkContext(conf) //[1] [2,3] [4,5] val rdd: RDD[Int] sc.makeRDD(List(1,2,3,4,5),3) //将处理的数据保存分区文件 rdd.saveAsText…

【Apifox Helper】自动生成接口文档,IDEA+Apifox懒人必备

文章目录前言&#x1f34a;缘由接口文档对接爽&#xff0c;整理起来真费脑⏲️本文阅读时长约10分钟&#x1f96e;前置条件1. IDEA开发工具2. Apifox(不必要)&#x1f3af;主要目标一秒生成接口文档&#x1f369;水图IDEA中项目接结构图生成到Apifox接口文档图&#x1f468;‍&…

Django框架之模板系列

模板 思考 : 网站如何向客户端返回一个漂亮的页面呢&#xff1f; 提示 : 漂亮的页面需要html、css、js.可以把这一堆字段串全都写到视图中, 作为HttpResponse()的参数,响应给客户端. 问题 : 视图部分代码臃肿, 耦合度高.这样定义的字符串是不会出任何效果和错误的.效果无法及时…

论文投稿指南——中文核心期刊推荐(矿业工程)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

springMVC概念(第一个入门案例)

目录 一、概念 1.什么是mvc&#xff1f; 2.mvc的工作流程&#xff1f; 3.什么是springMVC&#xff1f; 4.springMVC的特点 二、入门案例 准备工作&#xff1a; 正式代码例子 &#xff1a; 一、概念 1.什么是mvc&#xff1f; 答&#xff1a;MVC是一种软件架构的思想&a…

leaflet 上传包含shp的zip文件,在map上解析显示图形(059)

第059个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中本地上传包含shp的zip文件,利用shapefile读取shp数据,并在地图上显示图形。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果 文章目录 示例效果加载shapefile.js方式安装引用jszip(…

大数据框架之Hadoop:HDFS(四)HDFS的数据流(面试重点)

4.1HDFS写数据流程 4.1.1 剖析文件写入 HDFS写数据流程&#xff0c;如下图所示。 1&#xff09;客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件&#xff0c;NameNode检查目标文件是否已存在&#xff0c;父目录是否存在。 2&#xff09;NameNode 返回是否可…

c++函数指针进阶

c中有两种函数指针 普通函数指针成员函数指针 而对于成员函数指针&#xff0c;又分为两种 静态成员函数指针非静态成员函数指针 定义普通函数指针与静态函数指针的语法类似 void (*pa)(); 定义非静态成员函数指针 void (A::* pa)(); 在调用非静态成员函数时&#xff0c;实…

Spring循环依赖问题,Spring是如何解决循环依赖的?

文章目录一、什么是循环依赖1、代码实例2、重要信息二、源码分析1、初始化Student对Student中的ClassRoom进行Autowire操作2、Student的自动注入ClassRoom时&#xff0c;又对ClassRoom的初始化3、ClassRoom的初始化&#xff0c;又执行自动注入Student的逻辑4、Student注入Class…

8. QT_OpenGL--1. 在QtWidget中搭建OpenGL加载框架

1. 说明&#xff1a; 在 Qt 中使用 OpenGL&#xff0c;实际上时严格遵循一种代码开发框架的&#xff0c;在 QtWidget 中&#xff0c;需要使用 openGlWidget 控件&#xff0c;并自定义类&#xff0c;类中还需继承 QOpenGLWidget,QOpenGLFunctions_3_3_Core 两个类&#xff0c;并…

Word控件Spire.Doc 【Table】教程(14): 如何在C#中为word表格设置AutoFit选项

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

【沁恒WCH CH32V307V-R1的单线半双工模式串口通讯】

【沁恒WCH CH32V307V-R1的单线半双工模式串口通讯】1. 前言2. 软件配置2.1 安装MounRiver Studio3. UASRT项目测试3.1 打开UASRT工程3.2 编译项目4. 下载验证4.1 接线4.2 演示效果5. 小结1. 前言 该模块包含 3 个通用同步异步收发器&#xff08;USART1/2/3&#xff09;和 5 个通…

vivo 自研Jenkins资源调度系统设计与实践

作者&#xff1a;vivo 互联网服务器团队- Wu Qinghua 本文从目前业界实现Jenkins的高可用的实现方案&#xff0c;分析各方案的优缺点&#xff0c;引入vivo目前使用的Jenkins高可用方案&#xff0c;以及目前Jenkins资源的调度方案的设计实践和目前的落地运行效果。 一、前言 现…

微服务实战--高级篇:分布式事务seata

分布式事务 1.分布式事务问题 1.1.本地事务 本地事务&#xff0c;也就是传统的单机事务。在传统数据库事务中&#xff0c;必须要满足四个原则&#xff1a; 1.2.分布式事务 分布式事务&#xff0c;就是指不是在单个服务或单个数据库架构下&#xff0c;产生的事务&#xff0c…