深入理解字符串操作

 

可以证明的是,字符串操作是计算机程序设计中最常见的行为

目录

一、 不可变的String

二、String上的操作

1.String内部到底是如何工作的

2.String跟StringBuilder谁更好

3.StringBuilder都有哪些常用的API

三 、String类型和StringBuilder类型的相互转换

1、String-->StringBuilder

2、StringBuilder-->String

四、StringBuilder和StringBuffer的区别

五、String常用的一些API和基本的操作

1.常用API

2.检测是否相等

3.空串与null串

六、SpannableString的基本使用


一、 不可变的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 : 点击事件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值