Java的String(字符串详解)

news2024/11/18 6:31:08

字符串

1.字符串的常见构造方法

主要有三种,一种是直接使用常量去构造,要么使用new String来构造,或者还可以使用字符数组的形式。

public static void main(String[] args) {
// 使用常量串构造
String s1 = "hello";
System.out.println(s1);
// 直接newString对象
String s2 = new String("hello");
System.out.println(s1);
// 使用字符数组进行构造
char[] array = {'h','e','l','l','o'};
String s3 = new String(array);//将字符数组构造成一个字符串
System.out.println(s1);
}

String 类型本身并不存储数据,而是存储指向该字符串的引用,所以字符串类型是一个类,s1是一个引用,指向这个类。而这个类有两个成员变量,一个名称为value,这也是一个引用类型,指向一个字符数组,与C++类似,但是java中的字符数组是没有\0的。此外,字符串类型还有一个成员变量hash,这个暂时知道就行了。
在这里插入图片描述

2.常见的String类的方法

求长度

String.length()

public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "";
        char[] arr = {'h','e','l','l','o'};
        System.out.println(str1.length());//求字符串度,打印5
        System.out.println(str2.length());//求字符串度。打印0
        System.out.println(arr.length);//主要数组求长度和字符串求长度的区别,一个调用方法,一个调用属性
    }
}

在这里插入图片描述

判空

String isEmpty
判断是不是空字符串
在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        String str2 = "";
        System.out.println(str2.isEmpty());//返回的是true
    }
}

主要空字符串和空引用的区别

public class Test {
    public static void main(String[] args) {
        String str2 = "";
        System.out.println(str2.isEmpty());//返回的是true
        String str3 = null;
        System.out.println(str3.isEmpty());//报错 NullPointerException
    }
}

一个代表指向空字符串,一个代表不指向任何空间。

String对象的比较

queals方法

public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        System.out.println(str1 == str2);//实际比较的是两个字符串所在的地址,结果是false
        System.out.println(str1.equals(str2));//实际比较的是两个字符串的内容,结果是true
    }
}

eques方法在java中定义是这样的
在这里插入图片描述Object类里有一个equals方法,然后String类继承,并进行重写,重写后的equals方法如下

    public boolean equals(Object anObject) {
        if (this == anObject) {//如果两个指向的是同一个字符串
            return true;
        }
        if (anObject instanceof String) {//instanceof 关键字判断一个对象是否为一个类(或接口、抽象类、父类)的实例
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

public boolean equalsIgnoreCase(String anotherString)函数比较方法与equals是一样的,但是会忽略大小写。

public class Test {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("ABc");
        String s4 = new String("abcdef");
        System.out.println(s1.equalsIgnoreCase(s2)); // 不同字母,输出false
        System.out.println(s1.equalsIgnoreCase(s3)); // 相同字母,忽略大小写。输出true
        System.out.println(s1.equalsIgnoreCase(s4)); // 字符串不同,输出false
    }
}

String对象的比较

compare方法

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:

  1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
  2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public class Test {
    public static void main(String[] args) {
        String str1 = "hello";
        String str2 = "hello";
        String str3 = "word";
        System.out.println(str1.compareTo(str2));
        System.out.println(str3.compareTo(str2));//w的ASCIIz值为119,h的ASCII值是104 ;15= 1119-104
    }
}

在这里插入图片描述

String.java是这样重写compareTo函数的

 public int compareTo(String anotherString) {
        int len1 = value.length;//本字符串的长度
        int len2 = anotherString.value.length;//另外一个字符串长度
        int lim = Math.min(len1, len2);//去最小值
        char v1[] = value;//将字符串转化为数组
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;//返回的是首个不同字符的ASCII相减值
            }
            k++;
        }
        return len1 - len2;
    }

int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较

public class Test {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("ABc");
        String s4 = new String("abcdef");
        System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
        System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
        System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
    }
}

字符串查找

1char charAt(int index)

返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常

public class Test {
    public static void main(String[] args) {
        String name = "baixian";
        for (int i = 0; i < name.length(); i++) {
            System.out.println(name.charAt(i));//下标从0开始
        }
    }
}

结果是
b
a
i
x
i
a
n
String.java中对该方法定义如下

 public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);//越界,扔出警告
        }
        return value[index];//如果没错,就返回字符数组对应下标的元素
    }

2.int indexOf()

在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        String name = "baixian";
        System.out.println(name.indexOf('a'));//打印值为1
        System.out.println(name.indexOf('a',2));//从下标2的位置开始遍历,打印值为5
        System.out.println(name.indexOf("ai"));//在"baixian"主串中寻找子串(默认从0下标开始),返回子串的首字母所在的下标,打印值为1
        System.out.println(name.indexOf("ai",3));//在"baixian"主串中从3下标开始寻找子串,返回子串的首字母所在的下标,打印值为-1
    }
}

String.java中对该方法定义如下

 public int indexOf(int ch) {
        return indexOf(ch, 0);
    }
public int indexOf(int ch, int fromIndex) {//fromInde表示起始下标
        final int max = value.length;
        if (fromIndex < 0) {//起始下标小于0默认从从0开始
            fromIndex = 0;
        } else if (fromIndex >= max) {//起始下标大于字符串长度,返回-1
            // Note: fromIndex might be near -1>>>1.
            return -1;
        }

        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            for (int i = fromIndex; i < max; i++) {//遍历寻找
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }
public int indexOf(String str, int fromIndex) {
        return indexOf(value, 0, value.length,
                str.value, 0, str.value.length, fromIndex);
    }

当然还有,这里就不一一列举出来了。

3.int lastIndexOf()

int lastIndexOf(int ch) 从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int fromIndex)从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1
int lastIndexOf(String str) 从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, intfromIndex)从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返
回-1

public class Test {
    public static void main(String[] args) {
        String name = "baixian";
        System.out.println(name.lastIndexOf('a'));
        System.out.println(name.lastIndexOf('a',6));
        System.out.println(name.lastIndexOf("ai"));
        System.out.println(name.lastIndexOf("ai",4));
    }
}

在这里插入图片描述

字符串的转换

1.数值转字符串

注意:这里的转换并不是按照ASCII进行转换,而是直接变成字符形式
在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        String str1 = String.valueOf(1234);
        String str2 = String.valueOf(12.34f);
        String str3 = String.valueOf(false);
        String str4 = String.valueOf('1');
        String str5 = String.valueOf("1234");
        String str6 = String.valueOf(12.34);
        char[] arr = {'a','b'};
        String str7 = String.valueOf(arr);
        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);
        System.out.println(str4);
        System.out.println(str5);
        System.out.println(str6);
        System.out.println(str7);
    }
}

在这里插入图片描述

2.字符串转数字

// 字符串转数字
// 注意:Integer、Double等是Java中的包装类型,这个后面会讲到
int data1 = Integer.parseInt("1234");
double data2 = Double.parseDouble("12.34");
System.out.println(data1);
System.out.println(data2);

在这里插入图片描述
注:有关包装类的知识,可以去看https://blog.csdn.net/qq_53312143/article/details/126124615这位博主的博客

3.大小写转换

public class Test {
    public static void main(String[] args) {
        String str1 = "HELLO,你好";
        String str2 = "hello,你好";
        String str3 = "HEllo";
        System.out.println(str2.toLowerCase());//转换成小写
        System.out.println(str2.toUpperCase());//转换成大写
        System.out.println(str3.toLowerCase());
    }
}

4.字符串转数组

public class Test {
    public static void main(String[] args) {
        String s = "hello";
// 字符串转数组
        char[] ch = s.toCharArray();//toCharArray()字符串转化为字符数组
        System.out.println(Arrays.toString(ch));
        System.out.println();
// 数组转字符串
        System.out.println(s+"");//可以使用变量名+““的形式,将这个变量输出为字符型
        String s2 = new String(ch);
        System.out.println(s2);//或者用String方法,转换
    }
}

在这里插入图片描述

格式化

一般用于输出打印上

public class Test {
    public static void main(String[] args) {
        String str1 = String.format("%d-%d-%d",2019,9,14);
        System.out.println(str1);
    }
}

在这里插入图片描述

字符替换在这里插入图片描述

public class Test {
    public static void main(String[] args) {
        String str1 = "aabbabbaa";
        String ret1 = str1.replace('a','b');//将字符串中所有a替换为b
        System.out.println(ret1);
        String ret2 = str1.replace("ab","cc");//将字符串中所有ab替换为cc
        System.out.println(ret2);
        String ret3 = str1.replaceAll("a","b");//将所有字符都替换为b
        System.out.println(ret3);
        String ret4 = str1.replaceAll("a","ab");//将所有字符都替换为ab
        System.out.println(ret4);
        String ret5 = str1.replaceAll("a","b");//将第一个字符a替换为b
        System.out.println(ret5);
    }
}

在这里插入图片描述
注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.

字符串拆分

public class Test {
    public static void main(String[] args) {
        String str1 = "hello bai xian";
        String[] ret1 = str1.split(" ");//以空格为界限,分组,并存入字符串数组中
        String[] ret2 = str1.split(" ",2);///以空格为界限,分组,最多分两组
        System.out.println(Arrays.toString(ret1));
        System.out.println(Arrays.toString(ret2));
    }
}

在这里插入图片描述
但是需要注意
由于regex正则表达式的特殊性,所以一定要注意正则表达式在遇到转义字时的特殊情况

public class Test {
    public static void main(String[] args) {
        String str1 = "hello.bai.xian";
        String str2 = "hello.bai*xian";
        String[] ret1 = str1.split(".");//以.为分隔符需要注意,单独的.在正则表达式中表示所有字符,所以打印出来会是空字符数组
        String[] ret2 = str1.split("\\. ",2);//java中以\\代表一个\,所以\\.才表示真正的.
        System.out.println(Arrays.toString(ret1));
        System.out.println(Arrays.toString(ret2));
        String [] ret3 = str2.split("\\.|\\*");//用|表示或,表示两个不同的分隔符都可以分割
        System.out.println(Arrays.toString(ret3));
    }
}

在这里插入图片描述

有关正则表达式,可以看这位博主的博客
https://blog.csdn.net/senxu_/article/details/126109760

多次拆分

public class Test{
    public static void main(String[] args) {
        String str = "name=zhangsan&age=18" ;
        String[] result = str.split("&") ;
        for (int i = 0; i < result.length; i++) {
            String[] temp = result[i].split("=") ;
            System.out.println(temp[0]+" = "+temp[1]);
        }
    }
}

在这里插入图片描述

字符串的截取

String substring(int beginIndex) 从指定索引截取到结尾
String substring(int beginIndex, int endIndex) 截取部分内容(左闭右开)

public class Test {
    public static void main(String[] args) {
        String str = "abcdef";
        System.out.println(str.substring(5));//从下标5开始截取一直到字符末尾
        System.out.println(str.substring(0, 5));//从下标0开始到下标4结束
    }
}

删除空格

String trim() 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).

public class Test {
    public static void main(String[] args) {
        String str1 = "    hello world     ";
        System.out.println("["+str1+"]");
        System.out.println("["+str1.trim()+"]");
    }
}

字符串的不可变性

首先先看一个代码

public class Test {
    public static void main(String[] args) {
        String str1 = "abcde";
        String str2 = "abcde";
        String str3 = new String("abcde");
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);
    }
}

结果

true
false

整个程序执行过程是这样的,执行String str1 = "abcde";系统会在内存空间方法区中一块叫常量池的地方,这个里面存的是“abcde”这样一个字符数组,这个字符数组的地址假设为0x7,在栈中系统会创建一个名为str1的变量来,存储0x7。当进行第二行代码String str2 = "abcde";系统不会再在常量池里创建另外一个字符数组“abcde”了,而是依旧使用唯一的那一个"abcde",对str2进行实例化,所以str2中依旧存放的是0x7,所以第一个打印true;但是第三句代码执行了new()操作,实际在底层,他在堆区开辟了一块存储空间,用以存储常量池里面“abcde”的地址,然后再在栈区创建str3变量存储堆区的堆区的地址。所以第二行打印是false.
这里建议去看一下这篇博客,再去理解一下
//blog.csdn.net/liuyong1992/article/details/113835447

从上层定义上去看String的不可变性
在Java,jdk8中Sring类的部分定义如下图
在这里插入图片描述我们可以看到Sring类本身被final修饰,而Sring类里面的字符数组value,是被private final修饰的
final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内
容是可以修改的。

我们常说的String不能被修改是指String类里面的value数组不能更改,而不能更改的原因并不是因为final,而是因为private,这是一个私有变量,要想更改必须通过调用set方法,但是原生String类中并没有提供setvalue 方法,所以没有办法更改。

字符串的修改

public class Test {
    public static void main(String[] args) {
        String str1 = "abcde";
        str1 += "abc";
        System.out.println(str1);
    }
}

不要认为这里是对str1这个对象改变了,本质上创建了一个新的对象abcdeabc,将这个对象重新命str1,而不是将abcde这个对象进行了更改。
我们可以反汇编去看一下
在这里插入图片描述
实际上上述代码可以改为

public class Test {
    public static void main(String[] args) {
        String str = "abcde";
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(str);
        stringBuilder.append("abc");
        str = stringBuilder.toString();
        System.out.println(str);
    }
}

注意:只要两个字符串相加就会调用toSting函数,并不是说println函数调用才会调用toString

可以看出在对String类进行修改时,效率是非常慢的,因此:尽量避免对String的直接需要,如果要修改建议尽量
使用StringBuffer或者StringBuilder。

StringBuilder和StringBuffer

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilder和StringBuffer类。这两个类大
部分功能是相同的,这里介绍 StringBuilder常用的一些方法

StringBuff append(String str)

在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、double、float、int、long、Object、String、StringBuff的变量

public class Test {
    public static void main(String[] args) {
//        StringBuilder stringBuilder = "abc";//注意,这样是不成立的,因为"abc"默认是String类型,并不是 StringBuilder类型
        StringBuilder stringBuilder = new StringBuilder("abc");
        stringBuilder.append("abc");
        stringBuilder.append(10).append(19.5);//所有方法都是返回一个this 所以不会有那么多临时变量
        System.out.println(stringBuilder);
        
    }
}

下面看一个题目

String str = new String("ab"); // 会创建多少个对象
String str = new String("a") + new String("b"); // 会创建多少个对象

上面这个代码创建了多少对象
首先常量池里就会创建“ab”这样一个String对象,然后堆区里new了一个String对象,第二行代码,常量池里面创建两个String对象“a”和“b”,然后在堆区又new了两个String对象.然后两个字符串相加在底层是创建了StringBuilder对象,此外还要注意,调用toString 函数的时候,返回值里面,也会new一个String对象
在这里插入图片描述

至此,String 就讲解到这里

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

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

相关文章

order by排序语句的用法

文章目录 学习连接语法用法示例1、按单个列的值排序2、按多个列的值排序3、按指定的规则排序4、按中文拼音字母顺序5、Order by和where条件共用 数据库中常用order by关键字对结果集进行排序&#xff0c;又可使用desc和asc来进行指定规则的排序。 学习连接 数据库&#xff1a;…

chatgpt赋能python:单行for循环:Python编程的神器

单行for循环&#xff1a;Python编程的神器 Python是一门功能强大的编程语言&#xff0c;其中的单行for循环功能更是让它的编程效率倍增。在本文中&#xff0c;我们将探讨单行for循环是如何提升编程效率的。 什么是单行for循环 单行for循环是一种简单而强大的编程方式。它可以…

【利用AI让知识体系化】V8引擎相关知识

文章目录 I. 引言V8引擎的背景和概述 II. V8的设计和工作原理V8的整体设计V8的工作流程和运行机制V8在浏览器中的应用场景 III. 内存管理内存模型和内存管理策略垃圾回收机制和算法内存泄漏和内存优化 IV. JIT编译器JIT编译器的作用和优势V8的编译流程和编译器类型编译器优化技…

make的路径搜索

文章目录 前言一、VPATH二、vpath三、vpath 与 VPATH 的差别四、GPATH 用法总结 前言 在大型软件项目中&#xff0c;通常会存在多个目录&#xff0c;包含有源代码、头文件、库文件等不同类型的文件。在编译或链接时&#xff0c;需要指定相应的文件路径才能正确地进行构建。但是…

【计算机图形学】曲线和曲面(Bezier曲线 Bezier曲面)

模块5 曲线和曲面 一 实验目的 编写曲线和曲面的算法 二 实验内容 1&#xff1a;绘制Bezier曲线&#xff0c;并采用自行设计输入和交互修改数据点的方式。 实验结果如下图所示&#xff1a; 第一步&#xff1a;输入特征多边形的顶点个数&#xff0c;并按照顺序输入顶点的坐…

css3新增特性

1. 初始化 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, …

怎么通过ecs云服务器来给小程序发送消息

如果您想通过 ECS 云服务器向小程序发送消息&#xff0c;可以使用 WebSocket 技术。具体步骤如下&#xff1a; 1. 在 ECS 云服务器上搭建 WebSocket 服务器。您可以使用 Node.js、Java、Python 等编程语言来实现 WebSocket 服务器&#xff0c;具体实现方式可参考相关技术文档或…

Java笔记——KMP算法

KMP算法 文章目录 KMP算法KMP算法介绍主要逻辑Next数组KMP搜索代码解释生成next数组模式串匹配 源码展示 KMP算法介绍 KMP算法是一种串的模式匹配算法&#xff0c;用来求子串在主串的位置。是数据结构中比较难的一种算法。KMP算法的核心在于点在于如何利用子串生成next数组&am…

vim的使用、vim入门的三种常用模式、以及vim中常用的命令(超详细)

vim 入门的三种常用模式&#xff1a;分别是 1. 命令模式、2. 插入/编辑模式、3. 底行模式 1. 命令模式 控制屏幕光标的移动&#xff0c;字符、字或行的删除&#xff0c;移动复制某区段及进入Insert mode下&#xff0c;或者到 last line mode 如下&#xff0c;这个就是命令模式…

Numpy入门看这一篇就够了【史上入门最简单,开袋即食】

一边学习一边分享&#xff0c;好记性不如烂笔头 目录 一边学习一边分享&#xff0c;好记性不如烂笔头 NumPy问题思考&#xff1a; numpy是什么&#xff1f; 为什么要学习numpy&#xff1f; numpy是怎么组成的&#xff1f;特点是什么&#xff1f; numpy的应用场景有哪些&a…

css定位模式

1. 为什么需要定位&#xff1f; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"…

自动化专业求职方向与前景分析(合集)

自动化专业求职方向与前景分析 自动化专业求职方向 自动化专业是近几年高校教育改革中几个控制类专业合并后形成的宽口径专业&#xff0c;其实自动化就是搞控制的&#xff0c;用老师的话说就是控制一切可以控制的物理量&#xff0c;还说学自动化的人都要有控制的欲望。所谓控制…

Augmented Language Models(增强语言模型)

Augmented Language Models: A Survey 先上地址&#xff1a;https://arxiv.org/pdf/2302.07842.pdf 概率论难以支撑通用人工智能技术的诞生。—— Yann LeCun LLMs取得的巨大进展不再多说&#xff0c;它目前被诟病最多的问题是其会提供非事实但看似可信答案&#xff0c;即幻觉…

数组排序——从荷兰国旗问题到快速排序

本文首先将会介绍荷兰国旗问题&#xff0c;再讲述如何从该问题过渡到快速排序。 荷兰国旗问题 荷兰国旗问题&#xff08;Dutch National Flag Problem&#xff09;是由荷兰计算机科学家Edsger Dijkstra所提出&#xff0c;该问题的描述如下&#xff1a; 给定n个红、白、蓝三种颜…

JNDI学习笔记

最近在研究JNDI注入漏洞&#xff0c;就先浅浅的学习以下JNDI相关知识。 JNDI对各种目录服务的实现进行抽象和统一化。 在 Java 应用中除了以常规方式使用名称服务(比如使用 DNS 解析域名)&#xff0c;另一个常见的用法是使用目录服务作为对象存储的系统&#xff0c;即用目录服务…

SpringBoot --- 基础篇

一、快速上手SpringBoot 1.1、概述 SpringBoot开发团队认为原始的Spring程序初始搭建的时候可能有些繁琐&#xff0c;这个过程是可以简化的&#xff0c;那原始的Spring程序初始搭建过程都包含哪些东西了呢&#xff1f;为什么觉得繁琐呢&#xff1f;最基本的Spring程序至少有一…

大数据:VMware | Ubuntu | Hadoop | Spark | VMwaretools | Python 安装配置总结

一.环境概述 Linux发行版&#xff1a;Ubuntu虚拟机应用&#xff1a;VMware Workstation ProHadoop版本&#xff1a;3.1.3|伪分布式集群JDK版本&#xff1a;JDK1.8.0_162Spark版本:2.4.0Scala版本:2.12.8Python版本:3.6.8 | 3.7.16 二.Ubuntu 2.1 光盘文件 首先进入链接Down…

因为AI,我被裁了;MJ设计海报全流程;独立开发者每周收入2.3K美元;MJ常用参数超详细介绍 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 受 AI 影响&#xff0c;这 8 家公司开始裁员…… 为了搞清楚 AI 最近在影响哪些行业、哪些职业&#xff0c;作者花了三天事件找到了八…

基于SSM的网络在线考试系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 前言…

《Java并发编程实战》课程笔记(二)

可见性、原子性和有序性问题&#xff1a;并发编程 Bug 的源头 源头之一&#xff1a;缓存导致的可见性问题 在单核时代&#xff0c;所有的线程都是在一颗 CPU 上执行&#xff0c;CPU 缓存与内存的数据一致性容易解决。 因为所有线程都是操作同一个 CPU 的缓存&#xff0c;一个…