public class StringTest02 {
public static void main(String[] args) {
String s1=new String();//初始化新创建的 String对象,它代表了一个空字符序列。请注意,使用此构造函数是不必要的,因为字符串是不可变的。
System.out.println(s1);
String s2="";
System.out.println(s2);
//解码 利用数组将十进制转化为字符
byte[] array={65,67,68,69,70,71,72,73};
String s3=new String(array);
System.out.println(s3);
/*byte[] array1=new byte[3];//静态数组
array1[0]=67;array1[1]=69;array1[2]=67;
String s4=new String(array1);
System.out.println(s4);*/
String s5=new String(array,1,3);//选择从offset起到lenght的长度
System.out.println(s5);
char[] array3={'a','b','c','d'};//将字符数组转换成字符串
String s6=new String(array3);
System.out.println(s6);
String s7=new String(array3,1,3);//选中范围 一样
System.out.println(s7);
int[] array4={2,0,2,0,0,5,1,7,65,67,68,69};
String s8=new String(array4,2,10);//将十进制数组 转化为对应的字符
System.out.println(s8);
}
}
关于String字面赋值和new产生String对象的比较
public class StringTest1 {
public static void main(String[] args) {
//凡是双引号括起来的字符串常量都会在方法区内存的常量池中有一份
//而常量池中 同一个常量不会重复
String s="HelloWorld!";
String s1="HelloWorld!";
String s2=new String("HelloWorld!");
String s3=s2;
String s4=s1;
System.out.println("********=字面赋值的String比较********");
System.out.println(s==s1);//true
// s 和s1都是在方法区内存中字符串常量池中生成了一个HelloWorld! 而常量词中 不会有重复的
//所以栈内存中两个s s1 都指向同一个地址 所以为true
System.out.println(s.equals(s1));//String 重写了toString 方法
System.out.println(s==s4);//类似 方法区的常量池
System.out.println(s.equals(s4));
System.out.println("********=通过new产生对象赋值和字面赋值String比较********");
System.out.println(s2==s);//false虽然字符串的内容一样,但是==是比较地址 而s2是先通过new在堆内存中产生了一个对象
//而这个对象的内容是通过String产生的一个常量池,所以这个对象指向方法区的常量池
//而s是字面赋值 直接指向了方法区的常量池
System.out.println(s2.equals(s));//true String 重写了toString方法
System.out.println(s2==s3);//=赋值 内存地址一样
System.out.println(s2.equals(s3));
System.out.println("********方法区常量池不变原则********");
String s5="zhou";
String s6="zhou"+"xun";//先在常量池中新生成一个xun常量 然后用之前的zhou和xun进行拼接 新成立一个字符串常量
//所以常量池一个好处是 之前有的可以直接拿来用 不需要再次new创建
//所以 s5 s6 创建了三个字符串常量 都在常量池中 且不用的时候不会被回收
String s7=new String("zhou1111");//和上面类似
String s8=s7+"222";
System.out.println(s5);
System.out.println(s6);
System.out.println(s8);
}
}
关于StringBuffer和StringBuilder的使用
因为String产生的字符串对象,都是在方法区内存的常量池中,且都带有final关键字,所以其是不可修改的,在进行字符串拼接的时候,之前的字符串并不会被垃圾箱回收,所以,一旦拼接过程多了,会给内存带来压力
而StringBuffer和StringBuilder在进行字符串拼接的时候,之前的字符串可以被垃圾箱回收,因为二者都不带final关键字
而其中StringBuffer是线程安全的,带有关键字synchronized
对应StringBuilder是线程不安全 不带有关键字synchronized
public class StringBuffer01 {
public static void main(String[] args) {
StringBuffer sss=new StringBuffer();//字符串的拼接 之前直接用String+拼接的话 会一直留在常量池中 内存会不断变多
//主要区别在于String中有final 而StringBuffer没有final 所以就可以对这个进行修改 进行扩容 拷贝啥的
//在使用StringBuffer的时候尽可能初始化容量
//以减少底层数组的扩容次数,可以预估一下进行初始化扩容
//线程安全 因为它的方法都有synchronized
sss.append(52);
sss.append(33);
sss.append('a');
String s;
System.out.println(sss);
StringBuffer s1=new StringBuffer(20);
s1.append("asfd");
s1.append(111);
System.out.println(s1);
}
}
public class StringBuilder01 {
public static void main(String[] args) {
StringBuilder s=new StringBuilder();//StringBuilder 线程不安全 因为它没有关键字synchronized
}
}
String s3=s1+s2;//底层 StringBuffer.append("a").append("b").toString() 相当于new生成
String s=new String("a")+new String("b");//[a,b]在方法区的常量池中 [ab]在堆内存中的对象中
// s.intern();//将对象放入常量池中 JDK1.8 1.7之后的 1.6是复制一份到方法区中
System.out.println(s.equals("ab"));
System.out.println(s=="ab");//这个为什么 不等 因为有一个是对象
String ab=new String("ab");
System.out.println(ab=="ab");