JavaのString类这一篇就够了(包含StringBuffer_Builder)
1.🥗String类简介
在我们写代码的时候,String总是充斥着前前后后。
但你会不会经常力不从心,
“这个*** 字符串怎么** 转换不成功啊”
“*** 这个字符串到底是常量还是对象啊”
“这*** 字符串内存结构到底* * * 是什么啊”
“为啥我的字符串数组莫名其妙显示空指针异常啊”
“字符串常量和字符串对象应该怎么比较啊”
“这字符串数据不都是good嘛,怎么比一比又是false了***
“ 字符串怎么转化成int啊啊“
”String类为啥是final修饰的捏?“
”String?StringBuffer??StringBuilder???“
A:”什么?!String不是基本数据类型??它还有什么是我不知道的?“
B:”楼上的,你猜一猜String能被继承嘛?“
A:".....****"
哈哈,知识点看起来又多又杂,但我们好好缕一缕,它还是很好理解的。
在C语言中我们涉及到过字符串,但是在C语言中要表示字符串只能用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据方法分离开的方法不符合面向对象的思想,而字符串的应用又非常广泛,从上面的对话中就可以发现,哈哈哈。
因此Java语言专门提供了String类
我们不论是在写代码的时候,还是在校招的笔试当中,字符串都是常客。
面试也会经常问到关于String的问题
面试官:来来小伙子,简单背一下String类的源码呢? 小伙子:...我* 你****,(直接丢offer而去)
那么我们就带着对它的一些问题继续往下看
2.🍗 String常用方法和性质
2.1 🥩 字符串的构造
String类提供给我们的构造方式很多,最常见的有以下三种
//使用常量串来构造
String s1 = "hello Gremmie";
System.out.println(s1);
//直接new出String对象
String s2 = new String("hello 葛玉礼");
System.out.println(s2);
//使用字符数组进行构造
char[] array = {'h','e','l','l','o',' ','玉','米'};
String s3 = new String(array);
System.out.println(s3);
🍲 [注意]:
- String是引用类型,内部其实并不存储字符串本身,在String类的实现源码中,String类实例变量是这样的👇
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence,Constable, ConstantDesc {@Stableprivate final byte[] value;
//字符串实际上就存储在这个用final修饰的byte数组中private final byte coder;/** Cache the hash code for the string */private int hash; // Default to 0
/*** @author Gremmie102* @date 2022/4/21 15:49* @purpose : 比较字符串引用*/
public class StringTestDemo1 {public static void main(String[] args) {//s1和s2引用的是不同的对象,s1和s3引用的是同一个对象String s1 = new String("hello");String s2 = new String("world");String s3 = s1;System.out.println(s1.length());//获取字符串长度--输出5System.out.println(s1.isEmpty());//判断字符串长度是否为0,即是否为空}
}
- 在Java中用双引号""引起来的也是String类型对象
//打印"hello"字符串(String对象)的长度 System.out.println("hello".length);
2.2 🍙String对象的比较
字符串的比较是我们常用的操作,比如:字符串排序
- ==比较是否引用同一个对象
这里要注意的是,对于内置类型(基础数据),==比较的是变量中的值,对于引用类型==比较的是引用中的地址
public static void main(String[] args) {int a = 10;int b = 20;int c = 10;//对于基本类型变量,==比较两个变量中存储的值是否相同System.out.println(a==b);//falseSystem.out.println(a==c);//true//对于引用型变量,==比较两个引用变量引用的是否为同一个对象String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("world");String s4 = s1;System.out.println(s1==s2);//falseSystem.out.println(s2==s3);//falseSystem.out.println(s1==s4);//true}
- boolean equals(Object object)
按照字符大小的顺序比较
String重写了父类Object中的equals方法,Object中equals默认会按照==来比较,String重写equals方法之后,语法规则为:s1.equals(s2)
我们看看源码
用代码来给大家演示解释一下👇
public boolean equals(Object anObject){//1.先检测this和anObject是否为同一个对象比较,如果是的化则返回trueif(this == anObject){return true;}//2.检测anObject是否为String类型的对象,如果是的话那就继续比较//不是的话那就返回falseif (anObject instanceof String){String anotherString = (String)anObject;int n = value.length;//3.判断调用对象的this和anObject两个字符串的长度是否相同if (n == anotherString.value.length){char v1[] = value;char v2[] = anotherString.value;int i = 0;//4.按照字典顺序,从前往后逐个字符进行比较while(n-- != 0){if (v1[i] != v2[i])return false;i++;}return true;}}return false;}
然后我们再写一个main方法来实验一下
public static void main(String[] args) {String s1 = new String("hello");String s2 = new String("hello");String s3 = new String("HELLO");//s1,s2,s3引用的是三个不同的对象,因此==的比较结果都是falseSystem.out.println(s1 == s2);//falseSystem.out.println(s1 == s3);//false//equals比较:String对象中的逐个字符//虽然s1和s2引用的不是同一个对象,但是两个对象中放置的内容,所以输出true//s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出falseSystem.out.println(s1.equals(s2));//trueSystem.out.println(s1.equals(s3));//false}
- int compareTo(String s)方法:按照字典序进行比较
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。
具体比较方法为:
- 先按照字典顺序大小比较,如果出现了不等的字符,则直接返回这两个字符的大小差值
- 如果前k个字符相等(k为两个字符长度最小值)返回值为两个字符串的长度差值
源码如下👇
测试代码如下👇
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.compareTo(s2));//不同,输出字符差值-1System.out.println(s1.compareTo(s3));//相同输出0System.out.println(s1.compareTo(s4));//前k个字符完全相同,输出长度差值-3}
- int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写比较
源码👇
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));//不同,输出字符差值-1System.out.println(s1.compareToIgnoreCase(s3));//相同,输出0System.out.println(s1.compareToIgnoreCase(s4));//前k个字符完全相同,输出长度差-3}
2.3 🍱 字符串查找
这是一个超级实用的功能,String类中提供了一些常用的查找方法:
**方法 ** | ** 功能 ** |
---|---|
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出 IndexOutOfBoundsException异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch, int fromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,没有返回-1 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
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, int fromIndex) | 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1 |
这里大家要注意的是,上面表格中有 int ch 的参数,是char类型传进来强转换成int值,以此来方便程序进行,并不是说这个字符就是一个数哦
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
2.4 🥡 字符串的转化
我们在做题的时候,字符串的转化也是非常重要的,主要有以下几个
- 数值和字符串转化
public static void main(String[] args) {// 数字转字符串String s1 = String.valueOf(1234);String s2 = String.valueOf(12.34);String s3 = String.valueOf(true);String s4 = String.valueOf(new Student("Hanmeimei", 18));System.out.println(s1);System.out.println(s2);System.out.println(s3);System.out.println(s4);System.out.println("=================================");// 字符串转数字// 注意:Integer、Double等是Java中的包装类型,这个后面会讲到int data1 = Integer.parseInt("1234");double data2 = Double.parseDouble("12.34");System.out.println(data1);System.out.println(data2);
}
- 大小写转换
public static void main(String[] args) {String s1 = "hello";String s2 = "HELLO";// 小写转大写System.out.println(s1.toUpperCase());// 大写转小写System.out.println(s2.toLowerCase());
}
- 字符串转数组
public static void main(String[] args) {
String s = "hello";
// 字符串转数组
char[] ch = s.toCharArray();
for (int i = 0; i < ch.length; i++) {
System.out.print(ch[i]);
}
System.out.println();
// 数组转字符串
String s2 = new String(ch);
System.out.println(s2);
}
个人觉得这个方法是非常实用的!!
- String格式化输入
public static void main(String[] args) {
String s = String.format("%d-%d-%d", 2019, 9,14);
System.out.println(s);
}
2.5 🥟 字符串替换
那么在做一些算法题目时,我们需要替换字符串中的内容。
好家伙,直接上手利用toCharArray然后几个循环
没必要!
我们使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:
方法 | 功能 |
---|---|
String replaceAll(String regex, String replacement) | 替换所有的指定内容 |
String replaceFirst(String regex, String replacement) | 替换首个内容 |
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "_"));
System.out.println(str.replaceFirst("l", "_"));
//输出:
//he__owor_d
//he_loworld
🌭 【注意】:由于字符串是不可变的对象,替换不修改当前字符串,而是产生一个新的字符串
2.6 🫕 字符串的拆分
我们可以利用split将一个完整的字符串按照指定的分隔符划分为若干个子字符串
方法 | 功能 |
---|---|
String[] split(String regex) | 将字符串全部拆分 |
String[] split(String regex,int limit) | 将字符串以指定的格式,拆分为limit组 |
代码1👇实现字符串的拆分
String str = "hello world hello Gremmie" ;
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result){System.out.println(s);
}
代码2 👇字符串的部分拆分
public static void main(String[] args) {String str = "hello world hello Gremmie" ;String[] result = str.split(" ",2) ;for(String s: result) {System.out.println(s);}}
运行结果👇
拆分是特别常用的操作,一定要牢牢记住。 有一些特殊字符作为分隔符的话可能无法正确区分,需要加上转移符号
代码3👇拆分IP地址
public static void main(String[] args) {String str = "106.14.57.10" ;String[] result = str.split("\\.") ;for(String s: result) {System.out.println(s);}}
运行结果👇
🍫 【注意事项】:
- 字符"|","","+"*都得加上转义字符,前面加上 "" .
- 而如果是 "" ,那么就得写成 "\" .
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符.
代码4👇多次拆分
public static void main(String[] args) {String str = "name=Gremmie&age=19" ;String[] result = str.split("&") ;for (int i = 0; i < result.length; i++) {String[] temp = result[i].split("=") ;System.out.println(temp[0]+" = "+temp[1]);}}
运行结果👇
2.7 🥣 字符串的截取
现在我们遇到一种情况,你已经知道了索引,想要截取一段字符串 这个时候,你是不是又想上手循环了? 慢着!substring可以满足你!😋
方法 | 功能 |
---|---|
String substring(int beginIndex) | 从指定索引截取到结尾 |
String substring(int beginIndex, int endIndex) | 截取部分的内容 |
代码👇字符串的截取
public static void main(String[] args) {String str = "helloGremmie" ;System.out.println(str.substring(5));//是从下标为5截到最后的System.out.println(str.substring(0, 5));//下标索引范围左闭右开,[0,5)}
🍟 注意事项:
- 索引要从0开始
- 要注意前闭后开的规定,substring(0,5)表示包含0号下标的字符,不包含5号下标
2.8 🍰 字符串前后的空白删除
String中的trim()方法用来去掉字符串中的左右两个空格,保留中间的空格
代码示例👇观察trim()方法的使用
public static void main(String[] args) {String str = " hello Gremmie " ;System.out.println("["+str+"]");System.out.println("["+str.trim()+"]");}
运行结果👇
trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).
2.9🥫字符串常量池
字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。 如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。 在JDK6.0及之前版本,字符串常量池存放在方法区中在JDK7.0版本以后,字符串常量池被移到了堆中了。至于为什么移到堆内,大概是由于方法区的内存空间太小了
2.9.1 🥗 创建对象(一)
我们先来看看下面这段代码,创建String对象的方式是相同的嘛?
public static void main(String[] args) {String s1 = "hello";String s2 = "hello";String s3 = new String("hello");String s4 = new String("hello");System.out.println(s1 == s2); // trueSystem.out.println(s1 == s3); // falseSystem.out.println(s3 == s4); // false
}
上述程序创建方式类似,为什么s1和s2引用的是同一个对象,而s3和s4不是呢? 在Java程序中,类似于:1, 2, 3,3.14,“hello”等字面类型的常量经常频繁使用,为了使程序的运行速度更快、 更节省内存,Java为8种基本数据类型和String类都提供了常量池。
在系统设计中,我们尝尝会使用到”池”的概念。Eg:数据库连接池,socket连接池,线程池,组件队列。”池”可以节省对象重复创建和初始化所耗费的时间。对那些被系统频繁请求和使用的对象,使用此机制可以提高系统运行性能。 ”池”是一种”以空间换时间”的做法,我们在内存中保存一系列整装待命的对象,供人随时差遣。与系统效率相比,这些对象所占用的内存空间太微不足道了。
🍳class文件常量池
我们写的每一个Java类被编译后,就会形成一份class文件;class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种 字面量 (Literal)和 符号引用 (Symbolic References),每个class文件都有一个class常量池。 其中 字面量 包括:
- 文本字符串
- 2.八种基本类型的值
- 3.被声明为final的常量等;
符号引用 包括:
- 类和方法的全限定名
- 字段的名称和描述符
- 方法的名称和描述符。
🥯运行时常量池
运行时常量池存在于内存中,也就是class常量池被加载到内存之后的版本,是方法区的一部分。不同之处是:它的字面量可以动态的添加(String类的intern()),符号引用可以被解析为直接引用。 JVM在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。在解析阶段,会把符号引用替换为直接引用,解析的过程会去查询字符串常量池,也就是我们下面要说的StringTable,以保证运行时常量池所引用的字符串与字符串常量池中是一致的。
2.9.2 🐳 字符串常量池(StringTable)
在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。字符串常量由一个一个字符组成,放在了StringTable上。 在JDK6.0中,StringTable的长度是固定的,长度就是1009,因此如果放入String Pool中的String非常多,就会造成hash冲突,导致链表过长,当调用String#intern()时会需要到链表上一个一个找,从而导致性能大幅度下降;在JDK7.0中,StringTable的长度可以通过参数指定。
JDK版本 | 字符串常量池位置 | 大小设置 |
---|---|---|
Java6 | 方法区 | 固定:1009 |
Java7 | 堆 | 可设置,无大小限制,默认60013 |
Java8 | 堆 | 可设置,有限制,最小1009 |
总结🍔 :
- 单独使用””引号创建的字符串都是常量,编译期就已经确定存储到Constant Pool中
- 使用new String(“”)创建的对象会存储到heap中,是运行期新创建的;
- 使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中,String pool中存有“aaaa”;但不会存有“aa”。
- 使用包含变量的字符串连接符如”aa” + s1创建的对象是运行期才创建的,存储在heap中;只要s1是变量,不论s1指向池中的字符串对象还是堆中的字符串对象,运行期s1 + “aa”操作实际上是编译器创建了StringBuilder对象进行了append操作后通过toString()返回了一个字符串对象存在heap上。
- String s2 = “aa” + s1; String s3 = “aa” + s1; 这种情况,虽然s2,s3都是指向了使用包含变量的字符串连接符如”aa” + s1创建的存在堆上的对象,并且都是s1 + “aa”。但是却指向两个不同的对象,两行代码实际上在堆上new出了两个StringBuilder对象来进行append操作。在Thinking in java一书中285页的例子也可以说明。
- 对于final String s2 = “111”。s2是一个用final修饰的变量,在编译期已知,在运行s2+”aa”时直接用常量“111”来代替s2。所以s2+”aa”等效于“111”+ “aa”。在编译期就已经生成的字符串对象“111aa”存放在常量池中。
🍔 注意:
- 在JVM中字符串常量池只有一份,是全局共享的
- 刚开始字符串常量池是空的,随着程序不断运行,字符串常量池中元素会越来越多
- 当类加载时,字节码文件中的常量池也被加载到JVM中,称为运行时常量池,同时会将其中的字符串常量保存在字符串常量池中
- 字符创常量池中的内容:一部分来自运行时常量池,一部分来自程序动态添加
2.9.3 🦐 创建对象(二)
创建一个字符串的过程👇
String str = new String(“abc") 首先定义一个str的String类型的引用并存放在栈中 先在字符串常量池中找到该常量是否存在 如果存在则创建一个引用即可,则在字符串常量池中创建一个内容为"abc"的字符串对象。 执行new操作,在堆中创建一个指定的对象"abc",这里堆的对象是字符串常量池“abc”对象的一个拷贝对象 让str指向堆中“abc”这个对象(也就是存储这个对象的在堆中的地址)
在字节码文件加载的时候,先要将.Class文件中的常量池加载到内存中称为运行时常量池,此时也会将"hello"字符串保存到字符串常量池当中
说明:
- 在字节码文件加载的时候,"hello"和"world"就已经创建好了,并保存在字符串常量池当中
- 上图是代表直接用字符串常量进行赋值,即:
public static void main(String[] args) {String s1 = "hello";String s2 = "hello";System.out.println(s1 == s2); // true
}
- 当使用String s1 = "hello";创建对象的时候,先要在字符串常量池当中找,如果找到就将该字符串引用赋值给s1
🥨 intern方法
intern 是一个native方法(Native方法指:底层使用C++实现的,看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中。
public static void main(String[] args) {char[] ch = new char[]{'a', 'b', 'c'};String s1 = new String(ch); // s1对象并不在常量池中//s1.intern(); //调用之后,会将s1对象的引用放入到常量池中String s2 = "abc"; // "abc" 在常量池中存在了,s2创建时直接用常量池中"abc"的引用System.out.println(s1 == s2);
}
// 输出false
// 用intern之后,就会输出true
不同版本的Java会有不同的Intern来实现
🍜 面试题
请解释String类当中两种对象实例化的区别 JDK1.8中
- String str = "hello"
只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象
2. String str = new String("hello")
会开辟两块堆内存空间,字符串"hello"保存在字符串常量池中,然后用常量池中的String对象给新开辟的String对象赋值。
3. String str = new String(new char[]{'h', 'e', 'l', 'l', 'o'})
先在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内容拷贝到String对象中
2.10 🦑 字符串的不可变性
String是一种不可变对象. 字符串中的内容是不可改变的。
不可变性的体现在: 当对字符串重新赋值时我们需要重新制定一个内存区域,然后才能赋值,不能对原有的value进行赋值(也就是我们不能改变原有的value) 这里其实就是我们每当有一个对象就有一次给value赋值的机会,这次机会用了之后,也就是赋值之后,就不可以再改变了 所以我们在这里说,字符串的值一旦给定就不可以再修改,一旦尝试修改,就会创建一个新的字符串对象,让这个新的字符串去接收你想要成为的值。
- String类在设计时就是不可改变的,String类实现描述中已经说明了
String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:
- String类被final修饰,表明该类不能被继承
- value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中的内容可以修改。
- 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
它是需要新创建一个对象再对其进行修改的,并不是在原有的基础上进行修改
有些人说:字符串不可变是因为其内部保存字符的数组被final修饰了,因此不能改变。 这种说法是错误的,不是因为String类自身,或者其内部value被final修饰而不能被修改。 final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,但是其引用对象中的内容是可以修改的。
public static void main(String[] args) {final int array[] = {1,2,3,4,5};array[0] = 100;System.out.println(Arrays.toString(array));
// array = new int[]{4,5,6}; // 编译报错:Error:(19, 9) java: 无法为最终变量array分配值
}
为什么 String 要涉及成不可变的?(不可变对象的好处是什么?)
- 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
- 不可变对象是线程安全的.
- 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.
2.11 🐙 字符串的修改
**注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率 非常低下。 **
比如这么做👇
public static void main(String[] args) {String s = "hello";s += " world";System.out.println(s); // 输出:hello world
}
这么做中间创建了很多临时对象,非常浪费资源
那么我们应该怎么做呢?
在对String类进行修改时,效率是非常慢的,因此:尽量避免对String的直接需要,如果要修改建议尽量 使用StringBuffer或者StringBuilder。
3. 🦞 Java StringBuffer 和 StringBuilder 类
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
[图片上传失败...(image-b74cd7-1665193486312)]
在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。 StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。 由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
那么StringBuilder在append的时候具体是怎么做的呢?
public static void main(String args[]){StringBuilder sb = new StringBuilder(10);sb.append("Runoob..");System.out.println(sb); sb.append("!");System.out.println(sb); sb.insert(8, "Java");System.out.println(sb); sb.delete(5,8);System.out.println(sb); }
运行结果为: Runoob.. Runoob..! Runoob..Java! RunooJava!
而如果我们要求线程安全的话,就必须使用StringBuffer类了
public class Test{public static void main(String args[]){StringBuffer sBuffer = new StringBuffer("Gremmie:");sBuffer.append("http://");sBuffer.append("106.14.57.");sBuffer.append("10/");System.out.println(sBuffer); }
}
运行结果为👇
那么总结一下StringBuilder常用的一样方法:
方法 | 说明 |
---|---|
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index, char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str ) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start,int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
public static void main(String[] args) {StringBuilder sb1 = new StringBuilder("hello");StringBuilder sb2 = sb1;// 追加:即尾插-->字符、字符串、整形数字sb1.append(' '); // hellosb1.append("world"); // hello worldsb1.append(123); // hello world123System.out.println(sb1); // hello world123System.out.println(sb1 == sb2); // trueSystem.out.println(sb1.charAt(0)); // 获取0号位上的字符 hSystem.out.println(sb1.length()); // 获取字符串的有效长度14System.out.println(sb1.capacity()); // 获取底层数组的总大小sb1.setCharAt(0, 'H'); // 设置任意位置的字符 Hello world123sb1.insert(0, "Hello world!!!"); // Hello world!!!Hello world123System.out.println(sb1);System.out.println(sb1.indexOf("Hello")); // 获取Hello第一次出现的位置System.out.println(sb1.lastIndexOf("hello")); // 获取hello最后一次出现的位置sb1.deleteCharAt(0); // 删除首字符sb1.delete(0,5); // 删除[0, 5)范围内的字符String str = sb1.substring(0, 5); // 截取[0, 5)区间中的字符以String的方式返回System.out.println(str);sb1.reverse(); // 字符串逆转str = sb1.toString(); // 将StringBuffer以String的方式返回System.out.println(str);
}
从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可 以修改。频繁修改字符串的情况考虑使用StringBuilder
注意: String和StringBuilder类不能直接转换。
如果要想互相转换,可以采用如下原则 :
- String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
- StringBuilder变为String: 调用toString()方法
🍜 面试题
String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
- StringBuffer与StringBuilder大部分功能是相似的
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
- 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】 String str = new String("ab"); // 会创建多少个对象 String str = new String("a") + new String("b"); // 会创建多少个对象
相关文章:
JavaのString类这一篇就够了(包含StringBuffer_Builder)
1.🥗String类简介 在我们写代码的时候,String总是充斥着前前后后。 但你会不会经常力不从心, “这个*** 字符串怎么** 转换不成功啊” “*** 这个字符串到底是常量还是对象啊” “这*** 字符串内存结构到底* * * 是什么啊” “为啥我的字符串…...
C# dataGridView 导出表格 xls NPOI 2.4.1 版本
using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; try { SaveFileDialog fileDialog new SaveFileDialog(); fileDialog.Filter “Excel(97-2003)|*.xls”; if (fileDialog.ShowDialog() System.Windows.Forms.DialogResult.Cancel) { return; } //不允许dataGridView…...
秒杀项目的消息推送
目录 一、创建消费者 二、创建订单链路配置 1.定义RabbitMQ配置类 2.创建RabbitmqOrderConfig配置类 三、如何实现RabbitMQ重复投递机制 1.开启发送者消息确认模式 2.消息发送确认 ① 创建ConfirmCallBacker确认模式 ② 创建ReturnCallBack退回模式 3.创建生产者 …...
最近开发及 vue3 几个小总结
只是单纯记录一下最近维护了几个项目之后的感触,也只是在自己现在水平上面的一些感觉。发发牢骚,水水文章 是否过度封装 可能水平不够吧,在 axios 封装的时候,只是把响应和拦截还有一些全局的配置封装了一下,并没有加…...
代谢组学分享-花青素通过调节氨基酸代谢改善糖尿病肾病的肾功能
代谢组学文献分享,文章标题:Anthocyanin improves kidney function in diabetic kidney disease by regulating amino acid metabolism 发表期刊:Journal of Translational Medicine 影响因子:8.44 作者单位:中山大…...
超简单!pytorch入门教程:Tensor
超简单!pytorch入门教程:Tensor 一、pytorch安装 安装pytorch之前,需要安装好python(废话),还没安装过python的宝宝请先移步到廖雪峰的python教程,待安装熟悉完之后,再过来这边。 …...
如何使用COCO数据集,注意事项
COCO数据集可用来训练目标检测,分类,实例分割等。 下面简单说下如何使用这个数据集, 数据集下载可用如下的代码进行,以2017为例。 # Download the image data. cd ./images echo "Downloading MSCOCO train images ...&quo…...
金三银四跳槽季,JAVA面试撸题就来【笑小枫】微信小程序吧~
JAVA面试撸题就来【笑小枫】微信小程序啦~ 疫情已过,金三银四即将到来,小伙伴们是否有跳槽的打算呢?不管有没有,技术不能丢,让我们一起来撸题吧。 博主最近整理了一批面试题,包括JAVA基础、多线程与锁、Red…...
分享115个HTML电子商务模板,总有一款适合您
分享115个HTML电子商务模板,总有一款适合您 115个HTML电子商务模板下载链接:https://pan.baidu.com/s/158y3jP0tv7ZikxNOBMKsSg?pwdt970 提取码:t970 Python采集代码下载链接:采集代码.zip - 蓝奏云 import os import shuti…...
Python 字符串
字符串是 Python 中最常用的数据类型。我们可以使用引号 ( 或 " ) 来创建字符串。创建字符串很简单,只要为变量分配一个值即可。例如:var1 Hello World!var2 "Python Runoob"Python 访问字符串中的值Python 不支持单字符类型ÿ…...
总线定义,车载总线:车载etherNet or CAN
总线的定义总线是连接多个设备或者接入点的数据传输通路。这里面的关键词是多个设备或者接入点,所以不要过于局限的看待总线。根据互联的设备/接入点不同,传输的数据带宽,速率,距离不同和应用场景的不同都可能有不同的总线。不同的…...
Python(for和while)循环嵌套及用法
Python 不仅支持 if 语句相互嵌套,while 和 for 循环结构也支持嵌套。 所谓嵌套(Nest),就是一条语句里面还有另一条语句,例如 for 里面还有 for,while 里面还有 while,甚至 while 中有 for 或者…...
6万字电力行业系统解决方案光伏电站综合安防系统解决方案
【版权声明】本资料来源网络,知识分享,仅供个人学习,请勿商用。【侵删致歉】如有侵权请联系小编,将在收到信息后第一时间删除!完整资料领取见文末,部分资料内容: 目录 第 一 章背景与需求 1.1行…...
[Android Studio]Android 数据存储--SQLite数据库存储
🟧🟨🟩🟦🟪 Android Debug🟧🟨🟩🟦🟪 Topic 发布安卓学习过程中遇到问题解决过程,希望我的解决方案可以对小伙伴们有帮助。 📋笔记目…...
学校节能降耗减排方案——能耗监管平台的建设及效果剖析
摘要:作为崭新的校园能耗管理手段,能耗监测平台以传统管理方式无法企及的优势有力地提升了高校能源管理工作的水平.从而受到了相关管理者的青睐。本文梳理总结了高校能耗监测平台的基本组成和优势特点,同时对能耗平台建设和使用中…...
探索IP地址的应用
无论是互联网行业还是传统行业都会用到网络,作为企业如何维护网络安全,保障网站不被攻击,数据不被泄露等。这个时候我们就会通查询IP归属地,辅助企业解决安全问题。下面介绍一下ip归属地在各行业的具体应用。1.网安行业应用一&…...
点赞破万!阿里面试官总结的2022最新1685页Java面试宝典太全了
程序员入职企业的难度也在持续加大,如何顺利通过面试成为了大家所关心的话题。针对这些人群的需求,小编从阿里找来一份让大家在求职过程中旗开得胜!是从什么时候开始准备的?大概的我已经记不清了,可能是 4 月份左右开始…...
项目搭建规范
一. 代码规范 1.1. 集成editorconfig配置 EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。 # http://editorconfig.org root true [*] # 表示所有文件适用 charset utf-8 # 设置文件字符集为 utf-8 indent_style space # 缩进…...
8.Docker Machine
Docker Machine Docker Machine是Docker官方编排(Orchestration)项目之一,负责在多种平台上快速安装 Docker 环境。 Docker Machine项目基于Go语言实现,目前在Github上进行维护。 Docker Machine是 Docker 官方提供的一个工具&…...
如何配合使用ESLINT 和 PRETTIER
各自的作用 eslint:静态分析语法错误prettier:代码格式化工具(需要在IDE中安装prettier的插件) 使用方法: 安装 npm install eslint --save-dev // 创建 .eslintrc.json 文件 npx eslint --init npm install eslint-…...
学英语的优势已来,抓住这个机会
文 / 冰雪(微信公众号:王不留) ChatGPT大火,国外的商业价值还没找到,咱们这边已经开始变现了。谷雨小姐姐昨天在”一起学英语”微信群发了一张“收割韭菜”的文案截图。 299入社群,服务内容为:免…...
基于微信小程序云开发实现考研题库小程序项目(完整版)
今天手把手的带大家实现一款答题类的题库小程序,如果着急的话,可以直接去看文末源码.下载与项目部署。考研题库小程序云开发实战,完整版提供给大家学习。题库小程序,基于云开发的微信答题小程序,软件架构是微信原生小程…...
AI一点通:使用 ColumnTransformer 转换 Pandas DataFrame 的一个或多个列
在处理表格数据时,常常需要对一个或多个列进行转换以使它们更适合于分析或建模。在许多情况下,可以使用 Pandas 库轻松完成这些转换。然而,在处理大型数据集或构建机器学习管道时,使用 scikit-learn 的 ColumnTransformer 类来将转…...
【C语言】全局变量、局部变量和静态变量的区别
目录一、变量(一)全局变量(二)局部变量(三)静态变量(1)静态全局变量(2)静态局部变量二、常量一、变量 1、变量定义 变量的名称可以由字母、数字和下划线字符…...
血氧仪「上潜」,智能穿戴「下沉」
文|智能相对论作者|沈浪缺货、涨价、一“仪”难求......过去短短的几周,血氧仪市场持续走热,受到前所未有的关注,像鱼跃医疗这样的业内巨头更是赚得盆满钵满,但同时也深陷“发国难财”的舆论泥潭,说来也是唏嘘。尽管目…...
CPP2022-计算机类-期末考试
6-1 判断素数 分数 5 全屏浏览题目 切换布局 作者 李国瑞 单位 东北大学秦皇岛分校 设计一个函数,判断输入数据是否为素数,返回bool类型结果。 函数接口定义: bool prime(int num); 说明:num为正整数。 裁判测试程序样例&…...
【蓝桥集训】第二天——差分
作者:指针不指南吗 专栏:Acwing 蓝桥集训每日一题 🐾做题过程中首先应该注意时间复杂度问题🐾 文章目录1.改变数组元素2.差分3.差分矩阵1.改变数组元素 给定一个空数组 V 和一个整数数组 a1,a2,…,an。 现在要对数组 V 进行 n 次操…...
Spring Boot最核心的27个注解,你了解多少?
https://blog.csdn.net/ManuMAX/article/details/129017443 导读 Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较火热的微服务框架SpringCloud集成…...
css3弹性盒子
弹性盒子由弹性容器(Flex container)和弹性子元素(Flex item)组成。 弹性容器通过设置 display 属性的值为 flex 或 inline-flex将其定义为弹性容器。 弹性容器内包含了一个或多个弹性子元素。 display:flex; 修改排列方式: 0. direction: rtl; //(right-to-left),弹性子元素的…...
数据分析与SAS学习笔记2
SAS在企业使用的情况: SAS是一个很昂贵的商业软件。在企业中使用SAS比较多,在企业界中是比较流行,在学术界使用R比较多。 SAS简介:统计分析系统 处理生物分析数据。 SAS成为统计领域的国际标准软件,服务全球50000多家…...
广州企业网站建设哪家服务好/seo排名优化教程
注意事项需引入以下4项!!!import XLSX from xlsximport FileSaver from file-saverimport xlsxStyle from xlsx-style;import XSU from ./xlsxStyle.utils;// XLSX 、FileSaver 、xlsxStyle 都可以直接npm下载(引入1、2、3可npm下载)引入1:import XLSX from xlsx引入…...
最安全的网站语言/活动策划方案
ZooKeeper CAP定理: 一个分布式系统不可能同时满足以下三种,一致性(C:Consistency),可用性(A:Available),分区容错性(P:Partition Tolerance).在此ZooKeeper保证的是CP,ZooKeeper不…...
长沙网络安全公司/手机端关键词排名优化
xampp-建站集成软件包专门用来建设本地电脑的php运行环境,用来测试php网站代码,这款xampp官方版包括了最新版本的ApacheMySQLPHPPERL集成安装包。支持多语言:英文、简体中文、繁体中文、韩文、俄文、日文等。XAMPP实际上在以下几个方面大放光…...
购物网站图片素材/网上有卖网站链接的吗
B sort(A) %沿着输入参量 A的不同维的方向、从小到大重新排列 A中的元素。A 可以是字符串的、实数的、复数的单元数组。对于 A 中完全相同的元素,则按它们在 A 中的先后位置排列在一块;若 A 为复数的,则按元素幅值的从小到大排列ÿ…...
网页视频下载软件免费版/资源网站排名优化seo
给定两个整数 nnn 和 kkk,请你找到并输出能够整除 nnn 的第 kkk 小的正整数。 输入格式 一行,两个整数 nnn 和 kkk。 输出格式 输出能够整除 nnn 的第 kkk 小的整数。 如果不存在,则输出 −1−1−1。 数据范围 1≤n≤10151≤n≤10^{15}1≤…...
WordPress自定义json接口/肇庆seo优化
日志统计 #尺取法 #vector容器 #全局变量能开更大的空间哦~ 题目 小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是: ts id 表示在ts时刻编号id的帖子收到一个"赞"。 现在小明想统计有哪…...