java stringbuffer 赋值_Java常用类(String, StringBuffer, StringBuilder)

一、String类

String的实例化方式

通过字面量定义的方式

String str = "hello world";

通过new+构造器的方式

String str = new String("hello world");

面试题:String s = new String("asf");方式创建对象,在内存中创建了几个对象?

答:两个,一个是堆空间中new出来的,一个是char[ ]对应的常量池中的数据:“abc”

String类的内部细节

String表示字符串,使用一对“”引起来表示

String声明为final,不可被继承

String实现了Serializable接口,表示字符串是支持序列化的;实现了Comparable接口,表示String是可以比较大小的

String内部定义了final char[ ] value 用于存储字符串数据

String代表不可变的字符序列,简称:不可变性💦体现在如下三个方面

①对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值

②当对现有字符串进行连接操作时,也需要重新指定内存区域,不能对原有的value进行赋值

③当调用String的replace方法修改指定字符或者字符串时,也需要重新指定内存区域

通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串声明在字符串常量池中

字符串常量池中是不会存储相同的字符串的

String赋值的各种内存结构

String的部分构造器源码(用于辅助理解其不可变性以及两种初始化方式)

public final class String

implements java.io.Serializable, Comparable, CharSequence {

/** The value is used for character storage. */

private final char value[];

/**

* Initializes a newly created {@code String} object so that it represents

* an empty character sequence. Note that use of this constructor is

* unnecessary since Strings are immutable.

*/

public String() {

this.value = "".value;

}

/**

* Initializes a newly created {@code String} object so that it represents

* the same sequence of characters as the argument; in other words, the

* newly created string is a copy of the argument string. Unless an

* explicit copy of {@code original} is needed, use of this constructor is

* unnecessary since Strings are immutable.

*

* @param original

* A {@code String}

*/

public String(String original) {

this.value = original.value;

this.hash = original.hash;

}

/**

* Allocates a new {@code String} so that it represents the sequence of

* characters currently contained in the character array argument. The

* contents of the character array are copied; subsequent modification of

* the character array does not affect the newly created string.

*

* @param value

* The initial value of the string

*/

public String(char value[]) {

this.value = Arrays.copyOf(value, value.length); //见如上注释,copy的目的是对于数组的操作不会影响String的值

}

}

例子

public class StringTest1 {

public static void main(String[] args) {

String str1="abc";

String str2="abc";

String str3=new String("abc");

String str4=new String("def");

System.out.println(str1==str2);

System.out.println(str1==str3);

}

}

8cc179eb1145

内存结构图

(现在的知识有限,具体的细节我也不太懂,比如我不知道常量池里放的是否是对象,他们和数组的关系是不是应该这样放,我是按照视频里老师讲的和源码,自己理解为这样的,有错的话希望帮忙指出)

String的常用操作

连接字符串(+)

String s1="hello";

String s2="world";

String s3="hello"+"world";

String s4=s1+"world";

String s5=s1+s2;

String s6=(s1+s2).intern();

System.out.println(s3==s4);

System.out.println(s3==s5);

System.out.println(s4==s5);

System.out.println(s3==s6);

注意事项:

①常量与常量的拼接结果放在常量池中,且常量池中不会存在相同内容的常量

②只要其中一个是变量,结果就在堆中

③如果拼接的结果调用intern方法,返回值就在常量池中

题目:

final String str="123";

String str1=str+"abc";

String str2="123abc";

System.out.println(str1==str2); //true

解释:此时的str是常量,参照①

int length() 输出数组的长度,实际上是底层的数组的长度

char chatAt(int index) 返回index索引处的字符,实际上是return value[index];

🙊区别于C++的可以对字符串按照字符数组的方式进行访问修改,在java中,字符串是对象,应该使用对象的方法对字符串进行访问、修改等操作

boolean isEmpty() 判断当前数组是否为空,return value.length==0;

String toLowerCase() / toUpperCase() 将字符都变为小写或大写

String str1="ASDFG";

String str2=str1.toLowerCase();

//str1不变,印证了String的不变性

System.out.println(str1);

System.out.println(str2);

String trim() 返回值是去除原字符串首尾空格的副本,原字符串不变

boolean equals(Object obj) 比较字符串的内容是否相同

boolean equalsIgnoreCase(Object obj) 忽略大小写比较

String concat(String str) 将指定字符串连接到此字符串的结尾,等价于“+”

int compareTo(String str) 比较两个字符串的大小 负数,则当前对象小;整数,则str小

String substring(int beginIndex) 返回一个新的字符串,该字符串是从beginIndex开始截取到最后

String substring(int beginIndex, int endIndex) 返回一个新的字符串,该字符串是从beginIndex开始截取到endIndex-1的位置(左闭右开)

🤔在上述方法中,只要是对字符串进行了操作的,原字符串仍然保持不变,最终生成的结果是通过return的形式返回,所以对字符串操作的方法的返回值都是String类型的(再次注意字符串的不变性)

boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束

boolean startsWith(String prefic) 测试字符串是否以指定的前缀开始

boolean startsWith(String prefic,int toffset) 测试此字符串从指定位置开始的子串是否以指定的前缀开始

boolean contains(CharSequence s)当前字符串中是否包含字符序列s,CharSequence 是一个字符序列接口(典型的实现类是String,StringBuffer,StringBuilder), 此处可以传入一个String,但不能是字符数组

int indexOf(String str) 返回指定字符串在此字符串中第一次出现的索引位置

int indexOf(String str, int fromIndex) 返回指定字符串在此字符串中从fromIndex开始第一次出现的索引位置(可以用来寻找当前字符串中str出现的次数)

int lastIndexOf(String str) 返回最右出现的索引位置

int lastIndexOf(String str, int fromIndex) 返回最右出现的索引位置,从指定的索引开始反向搜索(从index开始向左搜索,如果index指的位置正好是最后一次出现的位置,则返回index)

String replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用newchar替换此字符串中出现的所有oldChar得到的

String replace(CharSequence target, CharSequence replacement) 返回一个新的字符串,使用指定的字符序列替换此字符串中所有匹配的字符序列

String replaceAll(String regex, String replacement) 使用给定的replacement替换此字符串中所有匹配给定正则表达式的子字符串

String replaceFirst(String regex, String replacement) 使用给定的replacement替换此字符串中匹配给定正则表达式的第一个子字符串

boolean matches(String regex) 判断此字符串是否匹配给定的正则表达式

String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串(符合正则表达式的部分不出现在最终结果中)

String[] split(String regex, int limit) 根据给定正则表达式的匹配拆分此字符串,最多不超过limit个,如果超过了剩下的全部放在最后一个元素中

String test="hhh,fff,ggg,aaa,ddd,eee,rrrr";

String[] res=test.split(",");

for(int i=0;i

System.out.println(res[i]);

}

System.out.println("-------------");

String[] res2=test.split(",",3);

for(int i=0;i

System.out.println(res2[i]);

}

8cc179eb1145

image.png

String与其他类型的转换

String与基本数据类型和包装类的转换

基本数据类型/包装类 --> String :String.valueOf()或者与空字符串进行连接

String --> 基本数据类型/包装类 :包装类.parseXXX()

(以int为例)

(好像valueOf方法都是把形参转换成当前类对象的)

public class StringTest1 {

@Test

public void test1(){

//int转String

int a=123;

String str1=String.valueOf(a);

String str2=""+a;

System.out.println(str1);

System.out.println(str2);

//String转int

int b=Integer.parseInt(str1);

System.out.println(b);

}

}

public void getChars(int start,int end,char c[],int offset)

该方法的作用是将当前字符串从start到end-1位置上的字符复制到字符数组c中,并从c的offset处开始存放

String与char[]的转换

String --> char[] : toCharArray()

char[] --> String : 构造器

@Test

public void test2(){

//string to char[]

String str="asf";

char[] chars=str.toCharArray();

for(int i=0;i

System.out.println(chars[i]);

}

//char[] to String

String newStr=new String(chars);

System.out.println(newStr);

}

String与byte[ ]转化

String转化为byte数组是字符编码的过程,底层都是以字节码的形式进行存储;byte数组转化为String是解码的过程。String转化为字节码的时候可以选择编码集,在utf-8中一个中文字符用三个字节表示,在gbk中用两个字节表示,所以解码使用的编码集应该与编码使用的相同,才能解出正确的结果

String --> byte[] : getBytes()

byte[] --> String : 构造器

@Test

public void test3(){

//String to byte[]

String str="123abc中国";

byte[] bytes_utf8=str.getBytes();

for(int i=0;i

System.out.print(bytes_utf8[i]+" ");

}

System.out.println();

byte[] bytes_gbk=null;

try {

bytes_gbk=str.getBytes("gbk");

for(int i=0;i

System.out.print(bytes_gbk[i]+" ");

}

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

System.out.println();

//byte[] to String

String res1=new String(bytes_utf8);

String res2=new String(bytes_gbk); //我的编译器使用的是utf-8解码,所以会乱码

System.out.println(res1);

System.out.println(res2);

}

8cc179eb1145

image.png

二、StringBuffer与StringBuilder

String、StringBuffer与StringBuilder三者的异同

String:不可变的字符序列;底层使用char[ ]存储

StringBuffer:可变的字符序列;线程安全的(synchronized),效率低;底层使用char[ ]存储

StringBuilder:可变的字符序列;(jdk1.5)线程不安全的,效率高;底层使用char[ ]存储

StringBuffer的部分源码

public final class StringBuffer

extends AbstractStringBuilder

implements java.io.Serializable, CharSequence

{

/**

以下用到的super构造器为

AbstractStringBuilder(int capacity) {

value = new char[capacity];

}

*/

/**

* Constructs a string buffer with no characters in it and an

* initial capacity of 16 characters.

*/

public StringBuffer() {

super(16);

}

/**

* Constructs a string buffer with no characters in it and

* the specified initial capacity.

*

* @param capacity the initial capacity.

* @exception NegativeArraySizeException if the {@code capacity}

* argument is less than {@code 0}.

*/

public StringBuffer(int capacity) {

super(capacity);

}

/**

* Constructs a string buffer initialized to the contents of the

* specified string. The initial capacity of the string buffer is

* {@code 16} plus the length of the string argument.

*

* @param str the initial contents of the buffer.

*/

public StringBuffer(String str) {

super(str.length() + 16);

append(str);

}

@Override

public synchronized int length() {

return count;

}

@Override

public synchronized int capacity() {

return value.length;

}

}

StringBuffer的容量问题

StringBuffer内部的两个重要成员变量value[ ](存放字符串)和count(有效字符的个数),初始化StringBuffer时会多开16个字符的大小作为value的长度,调用length()返回的是有效字符的个数count,调用capacity()返回的是value数组的真实长度

StringBuffer的扩容问题

如果要append的东西,底层数组放不下了(超出了capacity),需要扩容底层的数组。默认情况下,扩充为原来容量的2倍+2,同时将原有数组的元素复制到新数组中

具体可以查看append的源码

String由于不可变,效率最差,开发过程中如果字符串需要改变,建议使用StringBuffer和StringBuilder。并且,总是扩容也会影响到程序的效率,所以建议使用StringBuffer(int capacity)构造器,提前设置好容量

StringBuffer(StringBuilder)的常用方法

StringBuffer append(xxxx) 提供了很多的append方法,用于进行字符串拼接

StringBuffer delete(int start, int end) 删除指定位置的内容

StringBuffer replace(int start, int end, String str) 把[start,end)位置替换为str

StringBuffer insert(int offset, xxxx) 在指定位置插入xxxx

StringBuffer reverse() 把当前字符序列逆转

(以上操作都是在StringBuffer/StringBuilder原底层数组上进行操作,改变原底层数组存放的内容,返回类型是StringBuffer/StringBuilder,是因为执行了return this;,所以支持方法链的操作,例如str.append("123456").reverse();)

int indexOf(String str) 出现str的位置

String substring(int start, int end) 返回一个[start,end)的字符串

int length() 返回实际存放的元素的格式,与capacity区别开

char charAt(int n) 返回下标为n的字符

void setCharAt(int n, char ch) 将下标为n的字符替换为ch

例题:

创建一个字符串“ab12345cd",对字符串进行操作,使其变为”ab54321cd"

import org.junit.Test;

/**

* @Author: ssy

* @Description:

* @Date: Created in 9:28 2020/11/23

* @Modified By:

*/

public class StringTest2 {

@Test

public void StringBuilderTest(){

StringBuilder str=new StringBuilder("ab12345cd");

str.replace(2,7,(new StringBuilder(str.substring(2,7))).reverse().toString());

System.out.println(str);

}

}

写的时候还是应该多注意返回类型的;另外想不起库函数,这种题完全可以自己手写,和底层没有太大的差别

查找str1在str2中出现的次数

仅仅是熟悉一下相关函数的操作,不涉及算法知识,追求高效的话还是要学KMP算法

import org.junit.Test;

/**

* @Author: ssy

* @Description:

* @Date: Created in 16:38 2020/11/23

* @Modified By:

*/

public class AlgorithmTest2 {

@Test

public void test(){

String str1="aba";

String str2="ababahjjlkhhlkabaljlnmababa";

System.out.println(findCount(str1,str2));

}

/**

*

* @Description:

* 查找str1在str2中出现的次数

* @auther: ssy

* @date: 16:40 2020/11/23

* @param: [str1, str2]

* @return: int

*

*/

public int findCount(String str1,String str2){

int count=0;

int index=0;

if(str1.length()

while((index=str2.indexOf(str1,index))!=-1){

count++;

index++;

}

return count;

}

else return 0;

}

}

📚面试题

说出每一个输出的执行结果

@Test

public void testDebug(){

String str=null;

StringBuffer sb=new StringBuffer();

sb.append(str);

System.out.println(sb.length()); //4

System.out.println(sb); //"null" 没有引号,只是用来表示存储内容

StringBuffer sb1=new StringBuffer(str); //空指针异常

System.out.println(sb1); //由于出现异常不会执行

}

查看过源码的话,就会比较简单了

append的源码对于添加空字符串做了特殊处理,会将null这四个字符存放在数组中,所以长度增加4,数组中的内容为‘n’ ‘u’ ‘l’ ‘l’

构造器StringBuffer(str)中执行的操作为super(str.length()+16) 此时的str是空,所以会出现空指针异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值