Java基础16-String类(Buffer和Builder)
一、String类的本质是什么?
上边代码竟然输出的是一样的,我们进到String类的源码中
其实,字符串的本质就是字符数组, String 其实就是char数组的封装
二、字符串的分类
1.不可变得字符串String:当前对象创建完毕之后,该对象的内容是不能改变的,一旦内容改变就是一个新的类
2.可变的字符串:StringBuffer/StringBuilder,当前内容创建完毕之后,该对象的内容可以发生改变,内容改变时对象不变
我们输出上边两段代码,虽然引用名称相同,但是当我们重新赋值时,它的hashcode发生了变化,也就是说,str在内存中的地址发生了变化,str="索隆"虽然与str="路飞"名称相同,但实则是两个变量,也就是重新在内存中(常量池)开辟了一块空间。
三、String对象的创建
1.直接赋一个字面量:
String str1="abcd";
2.通过构造器
String str2=new String("abcd");
这两者有什么区别呢?别着急,请看下文
要说这个问题,那就必须要来了解一个内存中的区域,常量池。
常量池:专门存储常量的地方,都指的方法区中
* 编译常量池:把字节码加载进jvm时,存储的是字节码的相关信息(不研究)
* 运行常量池:存储常量数据(研究)
通过这个问题我们就来揭晓
String str4="abcd"和String str5=new String("abcd")的区别?
以上代码创建了几个String对象呢?
str4最多创建一个,最少不创建,如果常量池中已经存在abcd,直接引用不创建
str5最多创建两个String对象,至少创建一个,new关键字绝对会在堆空间创建内存区域,所以至少创建一个
我们再回头看第二种的hashcode不同的问题,实际上就是不同的值在常量池中开辟的空间其地址不同,当值变了。也就是这个引用指向的地址发生了变化
str和str10的hashcode竟然是一样的! 这下我们就明白了吧,只要是值相同,不管叫什么名字都指向的是同一个地址。
四、String对象的空值
1.表示引用为空(null):没有初始化,没有分配内存空间
String str3=null;
2.内容为空,已经初始化,分配了内存空间,不过没有内容
五、判断字符串非空
1.引用不能为空(null)
2.字符内容不能为空字符串
六、字符串的比较操作
1.使用==运算符,只能比较引用的内存地址是否相同
2.使用equals方法:在object类中和==相同,建议子类覆盖equals方法去比较内容
七、字符串的比较
1.单独使用""创建的字符串都是直接量,编译器已经确定存储到常量池中
2.使用new String("")创建的对象会存储到堆内存中,运行时期才创建
3.使用只包含直接量的字符串连接符如"aa"+"bb"创建的也是直接量,编译器就能确定,已经存储到常量池中
4.使用包含String直接量(无final修饰符)的字符串表达式(如"aa"+s1)创建的对象是运行期才创建的,存储在堆中
八、常用方法联系
//一、String练习,获取hello开头的文件名的后缀名 String filename="abc.java;hello.java"; //1.一份好来分割字符串,获取每个的名称和拓展名 String[] name=filename.split(";"); for (String names : name) { System.out.println(names); //2.判断每个名称是否以hello开头 if(names.startsWith("hello")) { //3.获取文件名的后缀名,最后一个点的后半截 names.lastIndexOf("."); //截取字符串 System.out.println(names.substring(names.lastIndexOf("."))); } } //二、单词首字母大写 String str7="willabcad"; //1.获取第一个字符,转换为大写 String first=str.substring(0, 1).toUpperCase(); //2.截取字符串从1到最后 String last=str.substring(1); System.out.println(first+last); //trim方法消除前后空格 System.out.println(" ab cd ".trim().length()); System.out.println(" ab cd ".length());
九、StringBuilder和StringBuffer
先来看一个小例子
//使用String/StringBuilder和StringBuffer拼接3万次 long begin=System.currentTimeMillis(); String str8=""; for(int i=0;i<30000;i++) { str8+=i; } long end=System.currentTimeMillis(); System.out.println(end-begin); //string做字符串拼接性能很低,原因是每次都要new新的对象 StringBuffer sb=new StringBuffer(""); long begin2=System.currentTimeMillis(); for(int i=0;i<30000;i++) { sb.append(i); } long end2=System.currentTimeMillis(); System.out.println(end2-begin2); StringBuilder sbr=new StringBuilder(""); long begin3=System.currentTimeMillis(); for(int i=0;i<30000;i++) { sbr.append(i); } long end3=System.currentTimeMillis(); System.out.println(end3-begin3); }
经过测试,sbr耗时最短,sb次之,所以拼接字符串使用stringbuffer或者stringbuilder
StringBuilder和StringBuffer都表示可变的字符串,功能方法相同
唯一的区别;
stringbuffer:使用了synchronized修饰符,表示同步,再多钱程并发时保证线程安全
stringbuilder:没有synchronized,不安全
常用操作
链式编程
append,deleteCharAt