String
String类
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。Java为了提高性能,静态字符串(字面量/常量/常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串。对于重复出现的字符串字面量,JVM会首先在常量池中查找,如果常量池中存在即返回该对象。
首先我们需要知道String是引用数据类型。当我们使用String str1="geng"的时候,我们就会从常量池中获取到该对象,然后赋值给str1。剩下的str3 str4是从栈中定义对象,所以两种是有本质区别的,一个是方法区(静态区)中的对象,一个是堆中的对象。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
/**
* Class String is special cased within the Serialization Stream Protocol.
*
* A String instance is written into an ObjectOutputStream according to
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
通过源代码我们可以看出:
1、String类是一个final类,不可以被继承
2、String实现了Serializable接口,表示字符串是支持序列化的
3、实现了Comparable接口,表示字符串可以比较大小
4、String内部是定义了char[] 数组,该数组存储字符串数据,其属性是final,表示String存储的字符串是不可变的。(所以当我们修改字符串的时候,它已经重新指定了内存地址)
对值传递包括String final类 和value这个final属性的一点理解:
public class test04 {
public static void exchange(OurTest ourTest){
ourTest.a=2;
}
public static void main(String[] args){
OurTest ourTest=new OurTest(1);
exchange(ourTest);
System.out.println(ourTest.a);//结果为2
}
}
class OurTest{
Integer a;
public OurTest(Integer a){
this.a=a;
}
}
public class test04 {
public static void exchange(OurTest ourTest){
ourTest=new OurTest(2);
}
public static void main(String[] args){
OurTest ourTest=new OurTest(1);
exchange(ourTest);
System.out.println(ourTest.a);//结果为1
}
}
class OurTest{
Integer a;
public OurTest(Integer a){
this.a=a;
}
}
为什么会产生这种情况呢?
形参是一个新定义的局部变量。定义的这个变量在栈中的地址值是不同的,因为不是同一个引用变量,但是他们存储的堆中的地址值是一样的。
public class StringTest001 {
String str=new String("good");
char[] ch={'t','e','s','t'};
public void exchange(String str,char[] ch){
str="test ok";
ch[0]='b';
}
public static void main(String[] args){
StringTest001 stringTest001=new StringTest001();
stringTest001.exchange(stringTest001.str,stringTest001.ch);
System.out.println(stringTest001.str);//good
System.out.println(stringTest001.ch);//best
}
}
在exchange方法中局部变量被赋值“test ok”的常量池中的地址值。
ch[0]=‘b’ ;相当于改变了堆空间中该地址的值。
对象的创建:

除了这些构造器之外,还可以通过字面量的方法赋值(String str=“geng”)
import org.junit.Test;
public class StringTest {
@Test
public void test01(){
String str1=new String("geng");
String str2="geng";
System.out.println(str1==str2);//false
System.out.println("***************************");
String str3=new String("geng");
System.out.println(str3==str1);//false
System.out.println(str3.equals(str1));//true
System.out.println("***************************");
String str4="geng";
System.out.println(str2==str4);//true
str4="peng";
System.out.println(str2==str4);//false
System.out.println("***************************");
String str5=str1;
System.out.println(str1==str5);//true
str5.replace("g","p");
System.out.println(str1==str5);//true
}
}
所以我们通过String s=new String("abc");的方式创建对象,在内存中创建了几个对象?通过String s="abc";呢?
第一种方式创建了两个对象,一个是堆空间中的String对象,另一个是常量池(方法区)中的(String的属性char数组)“abc” 对象。(如果常量池中已经创建了"abc"那么就创建了一个对象)
第二种当然就是一个或者不创建对象(常量池中是否有"abc"这个对象)
常用方法:
length()方法:
intern()方法:
返回对象在常量池中的地址(相当于返回value属性(char[])再常量池中的地址)
@Test
public void test03(){
String str1=new String("geng");
String str2=new String("geng");
String str3="geng";
System.out.println(str1.intern()==str2.intern());//true,在常量池中都是"geng"这个字符串
System.out.println(str1.intern()==str3.intern());//true
}
charAt()方法:
isEmpty()方法:
toLowerCase()方法:
使用默认语言环境,将String中所有的字符转换成小写
toUpperCase()方法:
使用默认的语言环境,将String中所有的字符都转换成大写
trim()方法:
返回字符串的副本,将字符串的前导空白和尾部空白忽略
equals(String string)方法:
比较字符串的内容是否相同(重写Object的方法)
equalsIgnoreCase(String string)方法:
忽略大小写的比较
concat(String string)方法:
将两个字符串进行拼接,相当于“+”
compareTo(String object)方法:
比较字符串的大小
substring(int beginIndex)方法:
获取一个新字符串,从beginIndex开始,一直到结束
substring(int beginIndex,int endIndex)方法:
获取一个新字符串,从beginIndex到endIndex(左闭右开)
endWith(String suffix)方法:
是否使用指定的字符串结束
startWith(String prefix)方法:
是否使用指定的字符串开始
startsWith(String prefix,int toffset)方法:
从指定索引位置开始的子字符串是否以prefix为前缀
contains(CharSequence s)方法:
当前字符串上是否包含指定的char值序列
indexOf(String string)方法:
返回指定字符串在此字符串中第一次出现处的索引
indexOf(String string,int fromIndex)方法:
返回指定字符串在此字符串中从指定索引开始第一次出现处的索引
lastIndexOf(String string,int fromIndex)方法
从指定索引处,从右向左寻找。
lastIndexOf(String string)方法
replace(char oldChar,char newChar)方法
replace(CharSequence target,CharSequence replacement)方法
replace(String regex(正则表达式) ,String replacement)方法
replaceFirst(String regex(正则表达式) ,String replacement)方法
matches(String regex)方法
split(String regex)方法
根据正则表达式的匹配拆分
split(String regex,int limit)方法
根据正则表达式的匹配拆分,最多不超过limit个
查找相关的函数找不到返回-1
toCharArray()方法
将String转换成char数组,我们可以使用构造器将char数组转换成String
getBytes()方法
将String转换成字节数组
@Test
public void test04() throws UnsupportedEncodingException {
String str="我爱你zhongguo";
byte[] bytes1=str.getBytes("utf-8");
System.out.println(Arrays.toString(bytes1));
byte[] bytes2=str.getBytes("gbk");
System.out.println(Arrays.toString(bytes2));
}
@Test
public void test04() throws UnsupportedEncodingException {
String str="我爱你zhongguo";
byte[] bytes1=str.getBytes("utf-8");
System.out.println(Arrays.toString(bytes1));
byte[] bytes2=str.getBytes("gbk");
System.out.println(Arrays.toString(bytes2));
String str1=new String(bytes1,"utf-8");
String str2=new String(bytes2,"gbk");
System.out.println(str1);
System.out.println(str2);
}

???????????
@Test
public void test05(){
String str="gengpeng";
String str1="geng";
String str2="peng";
final String str3="geng";
String str4=str1+str2;
String str5=str3+"peng";
System.out.println(str==str4);
System.out.println(str==str5);
}

String:
不可变
底层使用char[]
StringBuffer:
public StringBuffer() {
super(16);
}
如果是String我们使用空参构造器,他是创建一个char[0]数组,但是我们发现如果是StringBuffer,我们使用空参构造器,他是创建一个char[16]的数组。
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
就算我们使用代参构造器,他也会额外增加16个空间
@Test
public void test06(){
StringBuffer stringBuffer=new StringBuffer();
System.out.println(stringBuffer.length());//0
System.out.println(stringBuffer.capacity());//16
}
扩容问题:每次都是扩容为原来的一倍加2,如果还不够,直接就是当前新的字符串长度,不再有额外的空余。
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
我们在实际开发中也可以自己指定StringBuffer的容量,这样可以避免重复申请新的内存。
public StringBuffer(int capacity) {
super(capacity);
}
可变
线程安全,效率低一些(jdk1.0)
底层使用char[]
常用方法:
append()很多重载
delete(int start,int end)
删除指定位置的内容
replace(int start,int end,String str)
将start 到end(左闭右开)这段区间内的内容使用str替代
insert(int offset, )重载方法很多
(在指定位置插入)
reverse()
将字符串倒转
indexOf
substring()
charAt()
setCharAt(int n,char ch)
修改指定位置的字符
StringBuilder:
可变
线程不安全,效率高一些(jdk1.5)
底层使用char[]

浙公网安备 33010602011771号