java小白学习笔记——字符串string

1.1 简介。1

字符串可以理解为Unicode字符序列。每一个用双引号""引起来的字符串就是String类的一个实例。例如String s = “Java”

1.2 字符串拼接

可以使用+号来对字符串进行拼接。如果将字符串与非字符串用+号进行拼接时,非字符串会被转换成字符串(几乎任何一个Java对象都可以被转换成字符串)。当然,由于下面会讲到的不可变性,字符串拼接会带来一定的效率问题。

1.3 不可变性

String类没有提供方法来修改一个string中的某个字符。可以找到charAt方法,但不能找到修改其中某个字符的方法。事实上,所有看上去会修改字符串的方法都是返回了一个新的字符串。

public class ChangeString {
    public static void main(String[] args){
        String s = "HelloWorld";
        String newS = s.replace('o','a');
        String upperS = s.toUpperCase();
        System.out.println(s);
        System.out.println(newS);
        System.out.println(upperS);
    }
    /*
    out:
    HelloWorld
    HellaWarld
    HELLOWORLD
     */
    
}

可以看到,无论是使用replace还是toUpperCase方法,原有的字符串s都没有被改变。字符串"HelloWorld"永远由这几个字符组成,就像数字1永远是1一样,你不能修改它,但是可以修改字符串变量s让它指向一个新的字符串。
看一眼replace的源码也可以发现:
replace()方法源码当新的字符和旧的字符不一样时,返回的是一个新的字符串变量ret,而不是修改this。

可以认为各种字符串被放在一个字符串池当中,字符串变量指向池中的一个字符串,修改字符串就让这个变量指向池中另一个字符串,源字符串还在那里没有变(不知道这样理解对不对)。进行字符串复制时,原始字符串与复制的字符串共享相同的字符串。

现在有一个需求,需要修改某个字符串里面位置为2的字符为’a’。看起来找不到合适的方法直接修改这个位置的字符,为了修改,我们不得不使用字符串拼接:

String subS = s.substring(0,2);
String subS2 = s.substring(3);
String newS2 = subS + 'a' + subS2;

这样的拼接会比较麻烦,而且会产生很多中间字符串对象,效率比较低。如果真的追求效率,可以考虑StringBuilder

1.4 StringBuilder

如果确实有经常使用很多小字符串来拼接成一个长字符串的需求,为了避免创建过多的字符串对象,应该使用StringBuilder:

StringBuilder builder = new StringBuilder();
builder.append(subS);
builder.append('a');
builder.append(subS2);
String res = builder.toString();

另外,还有一个线程安全的StringBuffer类,不过效率会稍低一些。

1.5 字符串的比较

使用equals方法而不是==来进行字符串的比较。
Java虚拟机可能不总是将相同的字符串共享,而且对于substring和+等得到的字符串也并不一定共享:

String a = "abcdef";
String b = "abcdef";
String c = "abc";
System.out.println(a==b); //true?
System.out.println(a.equals(b)); //true
System.out.println(a.substring(0,3) == c); //false?

使用==来比较字符串可能会导致无法预计的间歇性的错误。

对于equals()方法,string类对它进行了重写,使得它比较的是两个字符串的内容。

1.6 空串和null

这二者是不一样的。空串是一个长度为0内容为空的字符串,可以这样检测:

if (s.length() == 0){
    //检测是否为空
}
if(s.equals("")){
	//检测是否为空
}
if (s == null){
    //检测是否为null
}

1.7 码点和代码单元

char类型是一个使用UTF-16编码表示Unicode码点的代码单元。大多数情况下,一个代码单元就表示现实中的一个字符,但是对于有些辅助字符,却需要两个代码单元来表示。
length方法返回的是代码单元的个数,如果字符串中含有一些辅助字符,那么返回的结果就跟现实生活中实际的“字符数”不一样。charAt()方法也是同样的道理。
如果想要保证绝对的正确,使用codePointCount()而不是length(),同理,使用codePointAt()而不是charAt()。

public class CodePoint {
    public static void main(String[] args){
        String s = "𝕆hi";
        int cpCount = s.codePointCount(0,s.length());
        int length = s.length();
        System.out.println(cpCount);// 3
        System.out.println(length);// 4
        int index = s.offsetByCodePoints(0,0);
        System.out.println(s.codePointAt(index));//控制台输出为120134
        System.out.println(s.charAt(0));// 控制台输出为?
    }
}

不过对于大多数日常用的字符,charAt和length不会有什么问题。


  1. 文章内容参考自《Java编程思想》《Java核心技术》,网络以及自己的思考,主要作为自己整理的笔记使用。理解上表达上可能存在错误,欢迎指正。 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值