String(字符串)是编程中最基础且高频使用的数据类型,它不仅是数据存储与展示的核心载体,更是连接用户交互、系统通信与数据处理的关键桥梁.String 看似 “简单”,却是贯穿编程全流程的 “基石”—— 从用户交互到数据处理,从系统通信到性能安全,它的使用频率和影响范围远超其他基础数据类型(如 int、boolean)。
1.字符串构造 String类提供的构造方式非常多,常用的就以下三种:
public static void main(String[] args) {
String testString1 = "hello world";
System.out.println(testString);
//使用字符串常量赋值
String testString2 = new String("hello world");
System.out.println(testString);
// 直接new String对象
char[] array = {'a','b','c','d','f'};
String testString = new String(array);
System.out.println(s);
//使用字符数组进行构造
byte[] bytes = {97,98,99,100};
String testString = new String(bytes);
System.out.println(str);
//使用字节数组 构造对象
}知道这几种常用的据可以了,其他的大家如果有兴趣可以参考Java在线的文档: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html 注意:String是引用类型,内部并不储存字符串本身。
2.字符串常量池 了解字符串的布局,首先我们要先了解到一个新的内存叫做:字符串常量池 字符串常量池在JVM是StringTable 类,实际是一个固定大小的HashTable(这个是有一部分数据结构的内容),不同的JDK版本的字符串常量池的位置以及默认大小是不同的: 一、字符串常量池的位置变化 字符串常量池的存储位置随 JDK 版本演进发生过两次重要迁移,核心原因是 JVM 内存模型的调整(如方法区实现的变化、元空间的引入)。 JDK 6 及之前 位置:存在于方法区(永久代,Permanent Generation)中。 说明:永久代是 HotSpot 虚拟机对方法区的具体实现,字符串常量池作为方法区的一部分,受永久代内存大小限制。 JDK 7 位置:从永久代迁移到堆内存(Heap)中。 原因: 永久代内存空间有限且容易发生内存溢出(OOM: PermGen Space)。 堆内存更大且可动态扩展,字符串常量池迁移后能减少因常量过多导致的内存溢出问题。 JDK 8 及之后 位置:仍在堆内存中(但方法区的实现从永久代改为元空间(Metaspace))。 说明:元空间默认使用本地内存(而非 JVM 堆内存),但字符串常量池并未随方法区实现的变化而迁移,仍保留在堆中,与 JDK 7 的位置一致。 二、字符串常量池的大小限制 字符串常量池的大小限制(即最多可存储多少个字符串常量)在不同 JDK 版本中通过不同参数控制,且默认值和调整方式存在差异。 JDK 6 及之前 大小受永久代内存大小限制(通过-XX:PermSize和-XX:MaxPermSize控制)。 无专门针对字符串常量池的大小参数,常量池容量间接由永久代总内存决定。 风险:若字符串常量过多,容易触发java.lang.OutOfMemoryError: PermGen space。 JDK 7 因迁移到堆内存,大小受堆内存总大小限制(通过-Xms和-Xmx控制)。 新增参数-XX:StringTableSize用于指定字符串常量池的哈希表容量(默认值为1009)。 哈希表容量越大,哈希冲突越少,字符串查找效率越高,但会占用更多内存。 JDK 8 及之后 仍受堆内存大小限制(同 JDK 7)。 XX:StringTableSize参数的默认值大幅提高: JDK 8 默认值为60013(JDK 7 为 1009)。 JDK 11 及之后默认值进一步增加到65536(2^16),优化了高并发场景下的性能。
3.字符串的内存存储
public static void main(String[] args){
String strTest1 = "Hello World";
String strTest2 = "Hello World";
System.out.println(strTest1 ==strTest2);
String st1 = "abc";
//这个字符串常量池最多创建一个对象
//引用位置在字符串常量池(StringTable)
String st2 = new String("abc");
//字符串至少创建一个对象
//引用位置是在堆内存
//这两个有的时候经常在面试中会被问到new String创建几个对象注意: 1.strTest进行储存的时候,“Hello World"回先存储到字符串常量的常量池当中 2.strTest再次存储的时候,会先检查字符串常量池当中是否存在”Hello World"常量,如果存在,则不需要在重复存储
public static void main(String[] args) {
String strTest1 = new String("Hello World");
String strTest2 = new String("Hello World");
System.out.println(strTest1 == strtest);
}
注意: 1.第一次存储的时候,会将“Hello World” 2.每次new都会在堆中实例化新的对象 3.存储strTest2的时候会使用常量池的“Hello world”对象进行存储
1.String对象的比较 字符串的比较是常见操作之⼀,比如:当你登录⼀个网站的时候,输入了用户名和密码之后,需要后台进行比较和对比。 1.1 ( == )是否比较引用同一个对象 注意:对于内置类型,比较的是变量中的值;对于引用类型比较的是引用中的地址。
public static void main(String args) {
int testA = 10;
int testB = 10;
int testC = 20;
//==对于基本引用类型变量,比较两个变量中存储的值是否相等
// ==的返回值是false 和 true
System.out.println(a == b); //true
System.out.println(a == c); //false
//对于引用类型的变量,==比较两个引用变量引用的是否为同一个的对象1.2 equals 方法:按照字典序比较(Unicode编码值大小排序) String类重写了父类的Object中的equals方法,object中equals 默认按照==比较,String重写equals方法后,按照如下规则进行比较。
public static void main(String[] args) {
String testA = "hello;
String testB = "hello;
String testC = "Hello;
System.out.println(testA.equals(testB));
System.out.println(testB.equals(testC));
// equals⽐较:String对象中的逐个字符
//判断引用的是否是同一个对象,放置的内容
}基本类型(int、double、char…):== 比较的是值。
int a = 10;
int b = 10;
System.out.println(a == b); // true引用类型(对象、数组、字符串…):== 比较的是 引用(地址),即两个变量是否指向同一个对象。
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // false,不是同一个对象String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2)); // true,内容一样
1.3compareTo 方法:按照字典序进行比较== 基本类型:值 引用类型:地址 .equals() 默认:地址 被重写后:内容
与equals 不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。 具体比较方式: 1.相同长度先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值 2.不同字符长度且如果前K个字符相等(k为两个字符长度最小值),返回值两个字符串的长度差值
public class TestString {
public static void main(String[] args) {
String testA = new String("hellof");
String testB = new String("hellob");
String testC = new String("hellofra");
String testD = new String("hellofta");
String testE = new String("abd");
System.out.println(testA.compareTo(testB));//4
System.out.println(testA.compareTo(testC));//-2
System.out.println(testA.compareTo(testD));//-2
System.out.println(testA.compareTo(testC));//-2 字符不等
System.out.println(testC.compareTo(testD));//-2 r-t
System.out.println(testA.compareTo(testE));//7
//第一个就不等了。所以第二条规则就两个字符串的第一个字符直接比较是7
}
}1.4 compareToIgnoreCase 方法:与compareTo的方式相同,但是忽略大小写比较
public static void main(String[] args) {
String testString1 = new String("hello");
String testString1 = new String("hg");
String testString1 = new String("Hello");
String testString1 = new String("helloworld");
System.out.println(testString1.compareToIngoreCase(testString2));//不同输出2
System.out.println(testString1.compareToIngoreCase(testString3));//相同0
System.out.println(testString1.compareToIngoreCase(testString4));//前K个字符完全相同,输出52 字符串查找 字符串查找也是字符串中⾮常常⻅的操作,博主做的表格有点不太好,将就看一下把:

package demostring;
public class TestStringIndex {
public static void main(String[] args) {
String s = "aaabbbcccaaabbbccc";
System.out.println(s.charAt(3)); //‘b’
System.out.println(s.indexOf('c')); //6
System.out.println(s.indexOf('c', 10)); //15
System.out.println(s.indexOf("bbb")); //3
System.out.println(s.indexOf("bbb", 10)); //12
System.out.println(s.lastIndexOf('c')); //17
System.out.println(s.lastIndexOf('c', 10)); //8
System.out.println(s.lastIndexOf("bbb")); //12
System.out.println(s.lastIndexOf("bbb", 10));//3
}
}3.转换 字符串转数值
int ret = Inter.parseInt("1234")数值转字符串
String str = String.valueOf(1234);字符串转字符
String str = "hello";
Char[] char = str.toCharArray();
for(char a:char){
System.out.println(a);
}格式化
public static void main(String[] args) {
String s = String.format("%d-%d-%d", 2024, 8,16);
//兄弟们,博主为什么写这个时间呢在评论区猜一猜吧(坏笑)
System.out.println(s);替换 String replaceAll(String regex,String repalcement) 替换指定内容
//String replaceAll(String regex,String repalcement) 替换指定内容
String str = "hello";
String str1 = "h";
String str2 = str.replaceAll(str1,"o");
System.out.println(str2);//oelloString replaceFirst(String regex,String replacement) 替换首个内容
String str = "hello";
String str1 = "l";
String str2 = str.replaceFirst(str1,"o");
System.out.println(str2);注意:字符串是不可以修改的,这个不是修改这原有的字符串,而是产生一个新的字符串。 5.字符串拆分 就是将一个完整的字符串按照自己的需求通过使用分隔符划分为若干个字符串 String[] split(String regex) 的功能是:将字符串全部拆分
String str = "hello world";
String[] str1 = str.split(" ");
for (String str2:str1) {
System.out.println(str2);
}
System.out.println(Arrays.toString(str1));
//这个只能打印完整的数组,博主当时学习的时候灵光一现想到这个了,结果不可以用
}
}String[] split(String regex,int limit) 的功能是:将字符串以指定的格式,拆分为limit组
String str = "hello world hello bit";
String[] result = str.split(" ", 2);
for (String s : result) {
System.out.println(s);//从第一个空格分开
}注意:有些特殊字符作为分割符,可能不好正确切割,需要加上转义

6.字符串截取 ⼀个完整的字符串之中截取出部分内容。 String substring(int beginindex)的功能:从指定的索引截取到结尾
String str = "helloworld";
System.out.println(str.substring(5));//world
//索引是从0开始的
System.out.println(str.substring(0, 5));//hello
Java的索引一般是左闭右开的,包含0不包含57.去除左右两边的空格 方法String trim() 的功能:去掉字符串中的左右空格,保留中间空格。
String str = " hello world ";
System.out.println(str.trim());
//hello world8.字符串的不可变性 1.String 类在设计时就是不可改变的。 2.所有涉及到修改字符串的内容操作就是创造一个新对象,改变的都是新对象 3.String 之所以不可以被修改的原因是内部数组因为私有成员
private final byte[] value;9.字符串的修改 字符串本身是不可以修改的,我们可以建立新的字符串的对象,Java中提供了StringBuffer 和 StringBuilder,想多了解一下去官方查看一下。 https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/StringBuffer.html