3.6 字符串

字符串的常用可想而知。
在Java里,字符串是一系列Unicode字符,用双引号表示。
例如:

String e = "";//空串,没有字符
String greeting = "Hello";//有5个字符

String类是Java自带的表示字符串的类。

1 子串

很显然,一个字符串可以划分为很多子串,甚至从数学的角度来说,它本身也是自己的子串嘛。
可以用字符串的一个subString()方法来获得子串。

//这里就取出了greeting字符串中的第0、1、2位置的字符,组成新的字符串
//字符串变量s就指向这个新的字符串"Hel",显然,这个字符串的长度是3 - 0 = 3
String s = greeting.subString(0, 3);

2 拼接字符串

用运算符+可以拼接两个字符串,形成新的字符串

String i = "I";//注意,只是一个字符串,不是字符,字符是用单引号
String love = "love";
String you =  "you";
String state = i + " " + love + " " + you + "!";// state = "I love you!"这里空格也是一个字符的

注意:如果+号两边有一个是字符串,那么Java会自动调用不是字符串的那个类的toString()方法,来使这个位置变成一个字符串来进行拼接

int price = 13;
String apple = "Apple:"
String message = apple + price;//message = "Apple:13",这里Java自动把数字13变成字符串"13"

3 字符串是不可变的

一个字符串实例,一旦创建完成,就是不可更改的。

String greeting = "Hello";
greeting = greeting.subString(0, 3) + "p!";
//表面上看,greeting变量是改变了,实际上是重新造了个新的字符串,greeting变量指向新的字符串而已
//如果你看String类的源码,可以知道,String类内部用数组实现保存字符,而数组长度是不可变的

这样做的坏处是,损失效率,好处是,编译器可以共享字符
实际应用中,很少改变字符串,更多的是比较,所以损失执行效率,提高系统性能。
如果确实要更改字符串,系统提供另外的类可以很方便的拼接字符串。

4 检测字符串是否相等

下面重新说明下==操作符的作用,这个操作符会得到一个布尔值,对或者错,比较什么呢?更为具体的是比较两边变量所指向的内存位置,如果是同一个位置那么,就是相等的,就返回true。

public class MyString {
    public static void main(String[] args){
        System.out.println("比较字符串String");
        String a = "A";
        String b = a;//这里面a和b变量都指向同一个字符串
        String c = new String("A");//虽然c里面也是"A",但是,new关键字却是新建了一个字符串
        if(a == b)
            System.out.println("a == b");//会输出
        if(a == c)
            System.out.println("a == c");//内存不一样,不会输出

        System.out.println("比较整型类Integer");
        Integer x = 1;//自动装箱,把1变成Integer类了
        Integer y = x;
        Integer z = new Integer(1);
        if(x == y)
            System.out.println("x == y");//会输出
        if(x == z)
            System.out.println("x == z");//内存不一样,不会输出

        System.out.println("比较基本数据类型int");
        int i = x;//自动拆箱,Integer类的x里面的值取出来了
        int j = i;
        int k = new Integer(1);
        if(i == j)
            System.out.println("i == j");//会输出
        if(i == k)
            System.out.println("i == k");//会输出

        System.out.println("比较基本数据类型int和整型类Integer");
        int xx = 1;
        Integer yy = xx;
        Integer zz = new Integer(1);
        if(xx == yy)//表面上比较的是两个类型,但是实际上Java自动把yy的值取出来,再比较的
            System.out.println("xx == yy");//会输出
        if(xx == zz)
            System.out.println("xx == zz");//会输出
        if(yy == zz)//两个都是Integer类型,Java就不取值比较了,所以不想等
            System.out.println("yy == zz");//内存不一样,不会输出
    }
}

这里写图片描述
从上面的例子,我们看出,Java编译器对基本数据类型是有优待的,只要有基本数据类型的==比较,就会取值比,但是关键是:String不是基本数据类型,所以String千万不能用==比较。

实际上,String的比较应该采用它的equals()方法。

    System.out.println("比较字符串String");
    String a = "A";
    String b = a;//这里面a和b变量都指向同一个字符串
    String c = new String("A");//虽然c里面也是"A",但是,new关键字却是新建了一个字符串
    if(a == b)
        System.out.println("a == b");//会输出
    if(a == c)
        System.out.println("a == c");//内存不一样,不会输出
    if(a.equals(c))
        System.out.println("a 和 c的值是一样的");//会输出

下面解释一下Java源码的equals()方法是怎么写的

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;//如果指向的内存一样,那么必然相等,不一样就继续比较呗
        }
        //如果传入的是String类型或其子类,那么还是有可能值是一样,就要继续判断           
        //如果类型都不一样,那么肯定不相等     
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {//如果长度相等,则继续比较每一个值
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])//如果有某一位置的字符不一样,则不相等
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

很明显看出,equals()方法比较的是String的值,也正是我们想要的那种。
String类型还有个equalsIgnoreCase()方法,是忽略字母的大小写来进行比较的。

5 空串和null

String str = "";//这是空串,
if(str.length() == 0)
    System.out.println("str的长度为0");//空串的长度就是0嘛
String str2 = null;//这个表明这个字符串,还没有指向任何字符串实例,没有指向嘛
String str3;//和上面语句一样一样的
if(str2 == null)//==是比较指向的,所以可以比较null
    System.out.println("str2为null");

6 代码点和代码单元

每个字符用了一个代码点,但代码点有的用了一个代码单元,有的用了两个代码单元。

char[] ch = Character.toChars(0x1D546);
System.out.printf("U+1D546 高代理字符: %04x\n", (int)ch[0]);//d835
System.out.printf("U+1D546 低代理字符: %04x\n", (int)ch[1]);//dd46
String str = new String(ch);
System.out.println("字符是:" + str);
System.out.println("代码单元长度: " + str.length());//2
System.out.println("第0个代码单元是: " + str.charAt(0));//给定位置的代码单元,由于未定义,返回?
System.out.println("第1个代码单元是: " + str.charAt(1));//给定位置的代码单元,由于未定义,返回?
System.out.println("代码点数量: " + str.codePointCount(0, str.length()));//1
System.out.println("代码点是: " + str.codePointAt(0));//返回给定位置开始或结束的代码点,120134

str = "12345" + str + "67890";
System.out.println(str.substring(0, 6));//45?
System.out.println(str.substring(0, 7));//45?
System.out.println(str.substring(0, 8));//45��6

//遍历打出每一个代码点
int i = 0;
while(i < str.length()){
    int cp = str.codePointAt(i);
    System.out.println(cp);
    if(Character.isSupplementaryCodePoint(cp))
        i += 2;//如果cp所在的位置是代码点的第一部分,执行此处
    else 
        i++;
}

关于这个知识点很难,我的建议是,如果你的字符串处理可能涉及到不常见的字符,请谨慎使用length()、chatAt()和subString()方法。

7 String类的API

  • char charAt(int index)
    返回指定位置的代码单元
  • int codePointAt(int index)
    返回指定位置的代码点
  • int offsetByCodePoints(int startIndex, int cpCount)
    以本字符串为基准,从指定位置startIndex开始,第cpCount个位置的代码点
  • int compareTo(String other)
    和其他的字符串按照字典顺序进行比较,如果本字符串在其他字符串前面,则返回一个负数,后面则返回一个正数,如果相等则返回0
  • IntStream codePoints()
    将本字符串,按照代码点流返回,再调用toArray()方法可以变成一个,代码点数组
  • new String(int[] codePoints, int offset, int count)
    对于指定的代码点数组,偏移offset,去count的长度,构建一个新的字符串
  • boolean equals(Object other)
    检测一个对象是否和本字符串相等
  • boolean equalsIgnoreCase(String other)
    检测一个字符串是否和本字符串相等,忽略大小写
  • boolean startsWith(String prefix)
    检测本字符串是否以一个指定字符串开始
  • boolean endsWith(String suffix)
    检测本字符串是否以一个指定字符串结束
  • int indexOf(String str)
  • int indexOf(String str, int fromIndex)
  • int indexOf(int cp)
  • int indexOf(int cp, int fromIndex)
    从fromIndex(如果有的话)开始向后查找,返回指定字符串或代码点的序号
  • int lastIndexOf(String str)
  • int lastIndexOf(String str, int fromIndex)
  • int lastIndexOf(int cp)
  • int lastIndexOf(int cp, int fromIndex)
    从fromIndex(如果有的话)开始向前查找,返回指定字符串或代码点的序号
  • int length()
    返回字符串的代码单元长度
  • int codePointCount(int startIndex, int endIndex)
    以本字符串为基准,返回指定范围(startIndex,endIndex-1)之间代码点的数量
  • String replace(CharSequence oldString, CharSequence newString)
    以本字符串为基准,将所有oldString替代为newString,构建新的字符串并返回
  • String subString(int beginIndex)
  • String subString(int beginIndex, int endIndex)
    按指定范围构件子串
  • String toLowerCase()
    全部小写构建字符串
  • String toUpperCase()
    全部大写构建字符串
  • String trim()
    裁剪本字符串首尾的空格
  • String join(Charquence delimiter, Charsequence… elements)
    以指定分隔符delimiter连接所有字符集elements,构建成一个字符串

8 联网查看在线文档

查看在线文档

9 构建字符串

如果要连接许多小的字符串,建议采用StringBuilder类。

StringBuilder sb = new StringBuilder();//构建一个StringBuilder对象
sb.append('I');//加入字符
sb.append(" ");//加入空格字符串
sb.append("love you!");//加入字符串
String state = sb.toString();//导出字符串

Java里面还有个StringBuffer类,基本上和StringBuilder相同,区别在于,效率低,但线程安全。
StringBuilder效率高,但线程不安全。
但是,大部分情况我我们并不需要跨线程构建字符串。所以StringBuilder使用的还是比较多的。
下面是StringBuilder的一些方法。

  • StringBuilder()
    构建StringBuilder对象,是空的。
  • int length()
    返回代码单元的长度
  • StringBuilder append(String str)
    加上一个字符串,并返回本身
  • StringBuilder append(Char c)
    加上一个字符,并返回本身
  • StringBuilder appendCodePoint(int cp)
    加上一个代码,并返回本身
  • void setCharAt(int i, char c)
    设置i位置为指定的字符
  • StringBuilder insert(int offset, String str)
    在指定位置插入字符串
  • StringBuilder insert(int offset,Char c)
    在指定位置插入字符
  • StringBuilder delete(int startIndex, int endIndex)
    删除指定范围内的数据
  • String toString()
    将内容导出为字符串
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值