Java的三种String(上):String

Java有三种字符串类型:String,StringBuilder与StringBuffer.你可能会想,为啥还要三种,直接String一种不就好了嘛?其实这三个类之间有很多不同之处,同时也有若干相同之处.

对于相同点,比如都是final类,所以不能被继承;都是对字符串进行操作等等等.

对于不同点,String与其它两个最大的不同点就是,String是不可变的,一旦创建了String对象,它就是不可更改的了,而其它两个都是可变的.再比如String可以使用String s = "字符串"的格式初始化,其它两种不可以.对于StringBuffer和StringBuilder,两者代码完全一样,只是StringBuffer的方法全部带有synchronized,说明它的线程安全,但是速度慢;反之StringBuilder线程不安全,但是速度快.

String为什么不能修改?

通过源码可以知道,三者的底层都是char[],这里就隐藏了String不可变的原因:

String:

        private final char value[];

StringBuffer与StringBuilder都继承自 AbstractStringBuilder类,在这个类中定义了一个char数组:

        char[] value;

 可以看到String的char[]是final的,也就意味着初始化之后就不能再改变,其他两种都没有用final修饰,也就代表可以任意改变.

String

字符串拼接

这个要单独拿出来说一说,因为可能跟大家想的不太一样,首先看看这个简单的代码:

        public class Test {
	        public static void main(String[] args) {
		        String str = "1";
		        System.out.println(str + "2");
	        }
        }

对生成的.class反编译之后,可以看到如下内容,注意→→→标识的位置.:

C:\Users\Administrator>javap -c c:\Test.class
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String 1
       2: astore_1
       3: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
→→→    6: new           #4                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #5                  // Method java/lang/StringBuilder."<init>":()V
      13: aload_1
→→→   14: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: ldc           #7                  // String 2
→→→   19: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
→→→   22: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      25: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      28: return
}

可以看到,创建字符串的时候,实际上是创建了一个StringBuilder对象(6),在(10)处进行了初始化(<init>),然后在(14)对我们定义的字符串"1"与空的StringBuilder进行拼接操作(append()),后面在利用"+"进行字符串拼接的时候,调用的依然是StringBuilder的append()(19),最后调用toString()转换为String对象(22),全程除了toString()之后返回的String就没有出现String对象.这里利用StringBuilder一是考虑了速度问题,二是考虑了String不可变的问题.

当然String也有自己的拼接方法concat().

构造器

有多种构造器来构造一个String对象,这里不列出已经弃用的构造器:

0  String()
1  String(byte[] bytes)
2  String(byte[] bytes, Charset charset)
3  String(byte[] bytes, int offset, int length)
4  String(byte[] bytes, int offset, int length, Charset charset)
5  String(byte[] bytes, int offset, int length, String charsetName)
6  String(byte[] bytes, String charsetName)
7  String(char[] value)
8  String(char[] value, int offset, int count)
9  String(int[] codePoints, int offset, intcount)
10 String(String original)
11 String(StringBuffer buffer)
12 String(StringBuilder builder)

把每个参数都解释一下,大家自己对照着匹配:

byte[] bytes                字节数组
Charset charset             字符集
int offset                  从这个下标开始
int length                  长度
String charsetName          字符集名称,该参数需要处理UnsupportedEncodingException(不支持的字符集异常)
char[] value                char数组
int count                   数量
int[] codePoints            Unicode字符数组,每个元素都是Unicode的编号
String original             已经存在的String对象
StringBuffer buffer         StringBuffer对象
StringBuilder builder       StringBuilder对象

下面用上面的构造器分别构造一个"abcde"字符串对象 :

        String string = "abcde";
        String string1 = new String(new  byte[]{97, 98, 99, 100, 101});
        String string2 = new String(new  byte[]{97, 98, 99, 100, 101}, "UTF-8");
        String string3 = new String(new byte[]{96, 97, 98, 99, 100, 101, 102}, 1, 5);
        String string4 = new String(new byte[]{96, 97, 98, 99, 100, 101, 102}, 1, 5, Charset.forName("UTF-8"));
        String string5 = new String(new byte[]{96, 97, 98, 99, 100, 101, 102}, 1, 5, "UTF-8");
        String string6 = new String(new byte[]{97, 98, 99, 100, 101}, "UTF-8");
        String string7 = new String(new char[]{'a', 'b', 99 , 'd', 101});
        String string8 = new String(new char[]{'?', 'a', 'b', 99 , 'd', 101, 102}, 1, 5);
        String string9 = new String(new int[]{96, 97, 98, 99, 100, 101, 102}, 1, 5);
        String string10 = new String("abcde");
        String string11 = new String(new StringBuffer("abcde"));
        String string12 = new String(new StringBuilder("abcde"));

方法 

charAt

char charAt(int index):返回index下标处的字符:

        String string = "abcdef";
        System.out.println(string.charAt(2));  //c

replace() 

String replace(char oldChar, char newChar) :将oldChar替换为newChar

String replace(CharSequence target, CharSequence replacement):将字符序列(target)替换为replacement

                               ↓↓  ↓  ↓ ↓
        String sp = "fsscscsjahbbscbdnbsb";
                       ↑↑↑↑      ↑↑  
        System.out.println(sp.replace('b', '0'));
        System.out.println(sp.replace("sc", "1"));


                  ↓↓  ↓  ↓ ↓
        fsscscsjah00sc0dn0s0
        fs11sjahbb1bdnbsb
          ↑↑      ↑

 

compareTo与equals()

int compareTo(String anotherString):按字典顺序比较字符串,具体来看看下面的源码.

boolean equals(Object anObject):两个字符串完全相同就返回true.

    public int compareTo(String anotherString) {
        int len1 = value.length;                //value的长度,也就是字符串的长度
        int len2 = anotherString.value.length;  
        int lim = Math.min(len1, len2);         //找出两个字符串长度的最小值
        char v1[] = value;                      //将调用者转换为char[]
        char v2[] = anotherString.value;        //将传入的参数转换为char[]

        int k = 0;                              //变量k                    
        while (k < lim) {                       //当k小于lim(两个字符串长度最小值)  
            char c1 = v1[k];                    
            char c2 = v2[k];
            if (c1 != c2) {                     //如果c1不等于c2
                return c1 - c2;                 //返回c1 - c2(char也可以用int赋值,反之亦可,只要不超过对应的范围)
            }
            k++;                                
        }    
        return len1 - len2;                     //如果比较的部分都一样
                                                //两个字符串中一个完全包含另一个字符串,
                                                //且只能是较长字符串的第一个字符开始与较短字符串完全一样,
                                                //就返回调用者的长度减去参数对象的长度.
    }

可以看看下面的代码:

        String string1 = "abcd";
        String string2 = "abcde";
        String string3 = "a1bc";
        System.out.println(string1.compareTo(string2));  //-1
        System.out.println(string2.compareTo(string1));  //1
        System.out.println(string1.compareTo(string3));  //49
        System.out.println(string3.compareTo(string1));  //-49
        System.out.println((int)'b'  - (int)'1');        //49

string1与string2是包含关系(string2从头开始完全包括string1),也就是while循环中不会触发return,就直接返回调用者的长度减去参数字符串的长度

string1与string3不存在包含关系,所以在while循环中会触发return,第一个字符'a'两者一样,第二个字符'b'和'2'不一样,就会触发return c1 - c2,这是合法的,因为char与int在char范围内可以任意转换.

equals(),不论怎么包装,只要内容一样就返回true,还有equalsIgnoreCase(),就是 忽略大小写差异.

        String string1 = "abcd";
        String string2 = "abcde";
        String string3 = new String(new StringBuilder(new String("abcd")));
        String string4 = "AbcD";
        System.out.println(string1.equals(string2));            //false
        System.out.println(string1.equals(string3));            //true
        System.out.println(string1.equalsIgnoreCase(string4));  //true

多个getBytes()

通过传入不同的参数来把字符串转换为字节数组,这里只看没有参数的那个:

        String string1 = "abcd";
        System.out.println(Arrays.toString(string1.getBytes()));  //[97, 98, 99, 100]

 indexOf与lastIndexOf()

        int indexOf(int ch)
        int indexOf(int ch, int fromIndex)
        int indexOf(String s)
        int indexOf(String s, int fromIndex)

        int lastIndexOf(int ch)
        int lastIndexOf(int ch, int fromIndex)
        int lastIndexOf(String s)
        int lastIndexOf(String s, int fromIndex)

indexOf():返回第一次出现该字符(字符串)的下标,传入第二个参数就从第二个参数指定的下标开始搜索,没找到就返回-1.

lastIndexOf():返回最后一次出现该字符(字符串)的下标,传入第二个参数的情况跟indexOf不太一样:

    public int lastIndexOf(int ch, int fromIndex) {
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            final char[] value = this.value;
            int i = Math.min(fromIndex, value.length - 1); //传入的index与字符串长度-1取较小值.
            for (; i >= 0; i--) {     //从下标i开始往前搜索
                if (value[i] == ch) {
                    return i;         //找到了就返回i
                }
            }
            return -1;                //没找到就返回-1
        } else {
            return lastIndexOfSupplementary(ch, fromIndex); //String内部的private方法
        }
    }

具体情况可以看看下面的代码,后面标注了对应字符运行结果:

        String string1 = "abcdcba";
        for (int i = 0; i <= string1.length(); i++) {
            System.out.println(i + "," + string1.lastIndexOf('a' , i));
        }
        //a : 0 0 0 0 0 0 6 6
        //b :-1 1 1 1 1 5 5 5
        //c :-1-1 2 2 4 4 4 4
        //d :-1-1-1 3 3 3 3 3

length():返回字符串长度:

        String string = "this is a String";
        System.out.println(string.length()); 

valueOf()

static valueOf():返回传入参数的字符串形式.

        static String valueOf(boolean b)
        static String valueOf(char c)
        static String valueOf(char[] data)
        static String valueOf(char[] data, int offset, int count)
        static String valueOf(double d)
        static String valueOf(float f)
        static String valueOf(int i)
        static String valueOf(long l)
        static String valueOf(Object obj)

下面给出了示例,不能一眼看出结果的都在注释标记了结果:

        System.out.println(String.valueOf(true));
        System.out.println(String.valueOf('c'));
        System.out.println(String.valueOf(new char[]{'a', 'b', 'c', 'd'}));
        System.out.println(String.valueOf(new char[]{'a', 'b', 'c', 'd', 'e', 'f'}, 1, 5)); //bcdef
        System.out.println(String.valueOf(Math.PI)); //3.141592653589793
        System.out.println(String.valueOf(Float.MAX_VALUE)); //3.4028235E38
        System.out.println(String.valueOf("asd%#%%^Gsggd".length()));  //13
        System.out.println(String.valueOf(123456789L));
        System.out.println(String.valueOf(new String("123987")));

subString()与split()

        String subString(int beginIndex)
        String subString(int beginIndex, int endIndex)

        String[] split(String regex)
        String[] split(String regex, int limit)

String subString() :截取字符串,返回切割后的字符串.一个参数是从给定下标到结束,两个参数是返回两个下标之间的:

        String sub = "qwertyuiop";
        System.out.println(sub.substring(2));    //ertyuiop
        System.out.println(sub.substring(1,6));  //werty

String[] split() :根据传入的正则表达式切割字符串,返回字符串数组.第二个参数是指切成几个元素,0等于没有传入第二个参数 :

        String sp = "1 23 456 78910 11 121314";
        String[] strings = null;
        for (int i = 0; i < 7; i++) {
            strings = sp.split(" ", i);
            System.out.println(i + "," + Arrays.toString(strings));
        }

        //0,[1, 23, 456, 78910, 11, 121314]
        //1,[1 23 456 78910 11 121314]
        //2,[1, 23 456 78910 11 121314]
        //3,[1, 23, 456 78910 11 121314]
        //4,[1, 23, 456, 78910 11 121314]
        //5,[1, 23, 456, 78910, 11 121314]
        //6,[1, 23, 456, 78910, 11, 121314]

contains(),startsWith()与endsWith()

这几个方法都是看是否包含的方法.

boolean contains(CharSequence s):包含s时返回true.(CharSequence:String实现的接口之一)

boolean startsWith(String prefix):字符串开头是否包含prefix.

boolean endsWith(String suffix):字符串末尾是否包含suffix.

        String sp = "1 23 456 78910 11 121314";
        System.out.println(sp.contains("1 12"));  //true
        System.out.println(sp.contains("112"));   //false
        System.out.println(sp.startsWith("1 2")); //true
        System.out.println(sp.startsWith("12"));  //false
        System.out.println(sp.endsWith("1314"));  //true
        System.out.println(sp.endsWith("12"));    //false

matches() 

boolean matches(String regex):匹配传入的正则表达式(regex).需要结合Pattern类使用.

其他方法

String toUpperCase():全部变成大写

String toLowerCase():全部变成小写.

        String sp = "AbCdEfGhIjKlMnOpQrStUvWxYz";
        System.out.println(sp.toUpperCase()); //26个字母全部大写
        System.out.println(sp.toLowerCase()); //26个字母全部小写

boolean isEmpty():判断给定字符串是否为空:

        String empty = "";
        String full = "fdgfthh";
        System.out.println(empty.isEmpty()); //true
        System.out.println(full.isEmpty());  //false

 char[] toCharArray():将字符串变成字符数组并返回.

        String string = "charArray";
        System.out.println(Arrays.toString(string.toCharArray())); //[c, h, a, r, A, r, r, a, y]

String trim():去掉前后的空格并返回.

        String trim = " needToTrim   ";
        System.out.println(trim.length());  //14
        trim = trim.trim();        
        System.out.println(trim);           //needToTrim
        System.out.println(trim.length());  //10

下一篇说说StringBuilder与StringBuffer.

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值