-
String
String是一个最终类 ,没有子类,所有的字符串常量都是String类的对象。
String创建完之后不能改变,底层是由不可改变的字符数组实现的(String底层由StringBuilder来实现的拼接,先把字符串底层字符数组的元素复制一份放到StringBuilder的可变数组中进行扩容(拼接),得到的拼接的结果就是新的可变字符数组,再有这个字符数组转成一个新的字符串,--就是把这个新的字符数组的元素拷贝一份放到一个新的不可改变数组里。)。所有的常量都要存储在常量池中,直接存储的就是真实值,String除外,他是存储的是引用,其他类型的常量直接存储常量值,字符串常量存储的指向字符数组的地址值。
如果常量池中已有字符串常量,后续出现的字符串常量重复了,如果重复了就用前面的----共享。
String s="a"; //开辟1个对象
s=s+"b";//new StringBuilder("a").append("b").toString(); 开辟4个对象 (里面有一个新的"ab")
下面是String案例的内存分析:
public class StringDemo1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//s1指向常量池
String s1="ab";
//s2指向堆,所以两个对象的地址值不相等
String s2=new String("ab");
//常量池中以及出现的字符串常量如果后续有重复的就用前面这一个 ---共享常量池
String s3="ab";
//byte b =128-1;
//和上面相同,在编译时期,只有常量进行运算的时候回进行编译优化,直接把计算结果赋值
String s4="a"+"b";
//s5指向堆,两个对象指向的内存空间不一样,地址值不一样
String s5 = "a";
//底层依赖另一个对象StringBuilder来完成
//toString() 返回一个新的字符串对象
String s6=new StringBuilder("a").append("b").toString();
s5=s5+"b";
System.out.println(s1==s2);//false
System.out.println(s1==s3);//true
System.out.println(s1==s4);//true
System.out.println(s1==s5);//false
//堆内不同区域,地址值不一样
System.out.println(s2==s5);//false
}
}
- 比较+和StringBuilder拼接效率
String[] ss={......};//100个
1、用+号拼接
String str=" ";
for(int i=0;i<ss.length;i++){
str+=ss[i]; //100次----300个对象
}//一共创建了301个对象
2、用StringBuilder进行拼接
StringBuilder sb = new StringBuilder(); 一个对象
for(int i=0;i<ss.length;i++){
sb.append(ss[i]); //一次循环一个对象 100次---100个
}
String str = sb.toString(); 一个对象
一个创建102个对象
在空间维度上,StringBuilder效率更高
public class StringDemo2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//1970.1.1到现在的毫秒值
long start = System.currentTimeMillis();
// //1.+拼接
// String str="";
// for (int i = 0; i < 100000; i++) {
// str+="a";
// }
// //结束时间
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000000; i++) {
sb.append("a");
}
String str = sb.toString();
long end = System.currentTimeMillis();
System.out.println(end-start); //+:2779ms StringBuilder:33ms
}
}
在时间维度上,StringBuilder效率更高。
综上所述:在进行大量数据拼接选择StringBuilder。
StringBuilder是线程不安全,但是效率高(jdk1.5)
StringBuffer是线程安全,但是效率低(jdk1.0)
- 重要方法 (String提供了大量的返回新字符串,不影响原字符串的方法)
-
charAt()-----根据字符串的下标返回指定的字符。
-
length()------返回字符串的长度值。
-
toCharArray()-----把一个字符串全部转成一个字符数组。
-
new String(char[] cs)------可以把字符数组部分信息转成一个新的字符串对象。
-
compareTo()-------返回的是两个字符串对象字典排序的差值(对应位置的字符的差值,如果差值为0直到一个字符串遍历结束返回的就是长度的差值)
-
concat()-------把新字符串拼接到原字符串的末尾,生成一个新字符串进行返回
-
contains()-------判断新字符串是否是原字符串的子串
-
startsWith()/endsWith()--------判断原串是否以指定的新串进行开头结尾
-
equals()--------重写Object中的equals,先比较地址值是否相等如果不相等再比较内容是否一致
-
getBytes()------可以根据指定的码表来返回一个字节数组,或者不指定码表就按我们默认系统平台码来进行编码返回一个字节数组。char c = '中'; 上述代码中的字符存储在.java文件中时默认按u8进行编码,对.java文件进行编译生成.class文件加载到内存中进行执行,此时这个代码中的字符默认按u16进行编码,内存执行完成之后要把内存的字节转成字符输出到程序中,如果没有指定编码就按默认系统平台码来进行编码(Windows中文版 GBK、Linux u8)。 new String(byte[] bs,int offeset,int length,Charset charset)---把部分字节数可以按照指定的码表进行转换成新的字符串对象,如果不指定就按默认系统码表转换。
-
hashcode()----返回的是字符串对象的哈希码值,重写了这个hashcode方法,根据字符元素顺序以及内容来算哈希值。
-
indexOf()-----返回指定新串(子串)在原串第一次出现的下标值,如果没有出现就返回-1
-
intern()--------把字符串对象的引用转向常量池。
-
isEmpty()-----是否为空串。 //内存有空间但是没有元素--空 内存空间没有开辟---null String str = new Striing();为空
-
replace()-------把原串中出现的所有指定字符换成新字符返回这样的新字符串
-
subString()-----按照给定的下标范围进行截取子串,把这个子串进行范围
-
toLowerCase()/toUpperCase()-----将字符串转为大小写
-
trim()-------对字符串的前面或者尾部出现的空格进行删除,不针对中间出现的空格
-
valueOf()-----将各个类型转换成字符串类型。
- 练习
1、输入一个字符串,给定字节数,按照这个字节数转成一个新的字符串,保证这个字符串不会出现?
import java.io.UnsupportedEncodingException;
public class StringText1 {
public static void main(String[] args) throws UnsupportedEncodingException {
// TODO Auto-generated method stub
//原串
String str = "字符串";
//给定字节数
int n=5;
//字符串转成字节数组
byte[] bs=str.getBytes("utf-8");
//按照给定的字节数转成新字符串
String s = new String(bs,0,n,"utf-8");
//判断新字符串是否出现了?
//新串的最后一个字符,和原串对应下标的字符相比
if(s.charAt(s.length()-1)!= str.charAt(str.length()-1)){
//转成字符数组
char[] cs=s.toCharArray();
//字符数组最后一个字符不转换
s = new String(cs,0,cs.length-1);
}
System.out.println(s);
}
}
2、输入一个字符串,返回字符串第一个字符出现的所有下标值。
import java.util.Arrays;
public class StringText2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str="wegfw43evf43";
int n=0;
while(n!=str.length())
{
n=str.indexOf("w",n);
if(n!=-1){
System.out.println(n);
n++;
}else {
break;
}
}
}
3、如何理解char[] cs int[] bs 打印bs为内存地址哈希值 cs为字符数组
int[] arr={2,3,4};
char[] cs={'a','b','c'};
//底层用valueOf转成了String
System.out.println(arr);//[I@6d06d69c
//底层没有进行valueOf
System.out.println(cs);//abc
//valueOf底层也用了toString方法进行拼接
System.out.println(cs.toString());//[C@7852e922