可以证明的是,字符串操作是计算机程序设计中最常见的行为
目录
三 、String类型和StringBuilder类型的相互转换
四、StringBuilder和StringBuffer的区别
一、 不可变的String
String对象是不可变的,所有看起来似乎在改变String对象的操作,都是在创建新的String对象,而最初的String对象丝毫未动。
1.测试String是否可变
public class StringTest {
public static void main(String[] args) {
String mString="android";
System.out.println(mString);
String mStringTwo=beToUp(mString);
System.out.println(mStringTwo);
System.out.println(mString);
}
public static String beToUp(String s){
return s.toUpperCase();
}
}
我们将mString传递给mStringTwo的时候实际上传递的是一份引用的拷贝,而该引用的对象一直呆在原来的物理位置上。 这里涉及到一个拷贝的问题,我们知道拷贝有深浅之分,那么我们的String的引用拷贝是深拷贝还是浅拷贝?
浅拷贝,是指原对象与拷贝对象公用一份实体,仅仅是对象名字不同而已(类似引用,即对原对象起别名),其中任何一个对象改变都会导致其他的对象也跟着它变。
深拷贝,就是为新对象开辟一块新的空间,并将原对象的内容拷贝给新开的空间,释放时就不会牵扯到多次析构的问题。
(下面是一段啰里啰嗦的话,可能不会太感兴趣,但是一定要看完,相信我!!!)
所以我们的String是深拷贝,自然而然的会在堆上再开一块内存,存在一个指针的东西,指向了原来的内容。我们知道一般的new 的String 是放在堆上的,但是我们的String s=“aaa”;这种又是怎么处理的呢?这种一般是放在常量池里,常量池是独立与堆、栈的存储空间,它的出现是为了快捷的创建某些对象。以提高其执行效率。我们知道基本数据类型是实现了常量池的,String不是啊?为啥还可以使用常量池?我们再思索一下,还是会有点眉目的,String的底层实现是字符数组,对!这里有个东西叫字符,字符是基本数据类型。所以String也可以使用常量池,JDK的版本一直在更迭,我们知道现在已经大概到12版本了,在某个版本的时候常量池已经放到堆里了。字符串常量池是全局的,JVM 中独此一份,因此也称为全局字符串常量池
好吧,可能方向有点偏,我们来看这个方法beToUp(); 我们难道真的希望beToUp()方法去改变参数吗?对于一个方法而言,参数是为方法提供信息的,不是让方法来改变自己的,正是有这种保障,我们的代码才会更加容易的编写。
二、String上的操作
String对象是不可变的,具有只读特性,所以指向它的任何引用,都不改变它的值,但这同时带来了一个问题,我们知道应用于String的“+”和“+=”是java中仅重载的两个运算符,严格意义上java是不允许重载操作符的。
1.String内部到底是如何工作的
我们来看一个这样的操作:String s=“a”+"b"+"c"+34+12.3;
这中间会产生好多个临时对象,若果不再需要,那么这可能就需要GC开始频繁的清理,短期内清理不掉,若果我们的new的时候又恰好产生了好多内存碎片,这对机器而言实在不太友好!
(软件设计中有一个通病,除非你让系统运行起来,动起来,否则你永远不了解这样做到底会有多糟糕)。
简单写一个测试的String类来看下String到底是如何运行的:(这是人类眼中的代码)
public class NewStringTest{
public static void main(String [] args){
String a="Android";
String s= a+"a"+"b"+"c"+123+456.1;
System.out.println(s);
}
}
好我们来看下jvm是怎么看待我编写的这段代码的(机器眼中我的代码是这样的?这都是些啥?汇编吗?)
机器的世界我不太懂,我们看这块的核心字眼,StringBuilder,why?怎么可能我明明写的是String,好吧,我们引出了今天的另一个bro StringBuilder,我们看到StringBuilder在疯狂的调用append方法,最后调一下toString方法,输出完事啦。我们仔细看上面这段机器眼中的代码,发现没有,new的字眼只出现了一次。
StringBuilder在某些层面上是优于String的,(比如它只new了一次)。还有设么好处,慢慢道来。。。。
到这里我们思考这样一个问题,我们是不是可以放心的以后随便的使用String了,你看编译器都自动帮我们进行了优化,内部都直接调用了StringBuilder了,我们还考虑那么多干嘛?拿起String就是用,不商量?
2.String跟StringBuilder谁更好
那么我们再来看一份代码?代码复代码,代码何其多?我生在明日,万事成蹉跎?明知下面有代码,偏向代码行!skr!
再来编写一个测试类,来看下效果,如下是两个新建String 和Stringbuilder的方法,
public class NewStringBuilder{
public static void main(String [] args){
}
public String initString(String [] fields){
String result="";
for(int i=0;i<fields.length;i++){
result+=fields[i];
}
return result;
}
public String initStringBuilder(String [] fields){
StringBuilder mStringBuilder=new StringBuilder();
for(int i=0;i<fields.length;i++){
mStringBuilder.append(fields[i]);
}
return mStringBuilder.toString();
}
}
我们看看机器眼中的它是如何的?
这是String的那个方法,我们看到这里的第35行,goto 没错,就是看他去哪了,我们看这里就是一个循环,我们再观察一下new在哪?发现了吧,new在循环里。我们再看下面这段,new在循环外,所以,StringBuilder还是有他的好处的,避免了重复的new StringBuilder,所以需要使用StringBuilder的时候我们还是要使用StringBuilder,数据量不大,需要new的对象不多的时候,我们使用String也是没有问题的。
3.StringBuilder都有哪些常用的API
StringBuilder提供了丰富且全面的方法,包括insert() repleace()substring()等常用的是append()和toString()我们简单的看几个方法;
(1)、length()
返回值类型:int 参数列表:无参 作用:返回字符串的长度
StringBuilder sb = new StringBuilder("HelloWorld");
int length = sb.length();
System.out.println(length);//10
(2)、append()
返回值类型:StringBuilder 参数列表:任意数据类型 作用:将参数追加到此字符串中
StringBuilder sb = new StringBuilder("HelloWorld");
sb.append("java");
System.out.println(sb);
(3)、insert()
返回值类型:StringBuilder 参数列表:int offset,任意数据类型 作用:将参数插入到offset索引处
StringBuilder sb = new StringBuilder("HelloWorld");
sb.insert(5, "java");
System.out.println(sb);
(4)、reverse()
返回值类型:StringBuilder 参数列表:无参 作用:反转此字符串
StringBuilder sb = new StringBuilder("HelloWorld");
sb.reverse();
System.out.println(sb);
三 、String类型和StringBuilder类型的相互转换
1、String-->StringBuilder
方法一: 调用StringBuilder的构造方法
String s = "HelloWorld";
StringBuilder sb = new StringBuilder(s);
System.out.println(sb);
方法二: 利用append()方法
String s = "HelloWorld";
StringBuilder sb = new StringBuilder();
sb.append(s);
System.out.println(sb);
2、StringBuilder-->String
调用toString()方法
StringBuilder sb = new StringBuilder("HelloWorld");
String s = sb.toString();
System.out.println(s);
四、StringBuilder和StringBuffer的区别
我们在提及StringBuilder的时候,或多或少会想到StringBuffer,那么他俩到底又有啥关系?
从java SE5以后引入了StringBuilder,在这之前我们使用的是StringBuffer,那么StringBuffer有啥好处呢?
StringBuffer是线程安全的,来看下源码:
@NonNull
public synchronized StringBuffer append(@Nullable String str) {
throw new RuntimeException("Stub!");
}
@NonNull
public synchronized StringBuffer append(@Nullable StringBuffer sb) {
throw new RuntimeException("Stub!");
}
@NonNull
public synchronized StringBuffer append(@Nullable CharSequence s) {
throw new RuntimeException("Stub!");
}
@NonNull
public synchronized StringBuffer append(@Nullable CharSequence s, int start, int end) {
throw new RuntimeException("Stub!");
}
不过我们一般操作字符串的话都是在单线程中,所以StringBuilder完全可以。
@NonNull
public StringBuilder append(@Nullable Object obj) {
throw new RuntimeException("Stub!");
}
@NonNull
public StringBuilder append(@Nullable String str) {
throw new RuntimeException("Stub!");
}
@NonNull
public StringBuilder append(@Nullable StringBuffer sb) {
throw new RuntimeException("Stub!");
}
@NonNull
public StringBuilder append(@Nullable CharSequence s) {
throw new RuntimeException("Stub!");
}
五、String常用的一些API和基本的操作
API查看链接 http://www.matools.com/api/java8
1.常用API
几个常用的API
length()
.indexOf()/lastIndexOf()
subString(int begin, int end)
trim();
charAt(int index)
toUpperCase()
toLowerCase()
2.检测是否相等
一定要使用equals()来比较,慎用“==”,等等是用来判断两个是否在同一个位置上,jvm如果始终将相同的字符串共享,那么是可以使用==的,但是实际上只有常量是共享的,但我们常用的+ substring等操作的结果并不是共享的,所以避免间歇性错误,我们一定要规范的使用equals()。
3.空串与null串
(1)str=“” 是长度为0的串
这样判断
if(str.length==0)
if(str.equals(""))
需要注意的是空串也是一个对象。
(2)检测字符串是否为null
if(str==null)
null上操作可是会空指针哦!!!!
(3)判断一个字符串既不是空串也不是null
if(str!=null&&str.length!=0)
六、SpannableString的基本使用
我们再说一些跟Android有关的,我们想不想自定义我们的字符串啊?有没有方法啊?
看下面---------->
上个小图看下:
基本属性拿去,自己研究一下
SpannableString的基本属性
BackgroundColorSpan : 文本背景色 ForegroundColorSpan : 文本颜色 MaskFilterSpan : 修饰效果,如模糊(BlurMaskFilter)浮雕 RasterizerSpan : 光栅效果 StrikethroughSpan : 删除线 SuggestionSpan : 相当于占位符 UnderlineSpan : 下划线 AbsoluteSizeSpan : 文本字体(绝对大小) DynamicDrawableSpan : 设置图片,基于文本基线或底部对齐。 ImageSpan : 图片 RelativeSizeSpan : 相对大小(文本字体) ScaleXSpan : 基于x轴缩放 StyleSpan : 字体样式:粗体、斜体等 SubscriptSpan : 下标(数学公式会用到) SuperscriptSpan : 上标(数学公式会用到) TextAppearanceSpan : 文本外貌(包括字体、大小、样式和颜色) TypefaceSpan : 文本字体 URLSpan : 文本超链接 ClickableSpan : 点击事件