本博文为学习【从菜鸟到高手演变】系列博客http://blog.csdn.net/zhangerqing 所作笔记。

前言:字符串在任何语言中都是一个非常重要的概念,在学习java的过程中,java字符串的学习是必不可少的。Java中的字符串处理主要有下面三个类来处理的:StringStringBufferStringBuilder

一、String

1String简介

1.1 初始化

一般由String声明的字符串,长度是不可变的,这也是它与StringBufferStringBuilder最直观的一个区别。一般初始化方式:String s = "hello world";经过这条语句,JVM栈内存中产生一个s变量,堆内存中产生hello world字符串对象。s指向了hello world的地址。像上面这种方式产生的字符串属于直接量字符串http://zcyoung.cn/?id=74)对象,JVM在处理这类字符串的时候,会进行缓存,产生时放入字符串池,当程序需要再次使用的时候,无需重新创建一个新的字符串,而是直接指向已存在的字符串。看如下程序

class StringTest{
    public static void main(String[] args){
        String s1 = "hello world";  
        String s2 = "hello world";  
        System.out.println(s1 == s2);  
    }
}

程序输出为true,因为s1s2都指向了同一字符串,地址相同。我们常说,String的一个很大的特点,就是它是一个“不可变的字符串”,就是说,当一个String对象完成创建后,该对象的内容就固定下来了,但是为什么还会有下面这种情况呢?

 

public class StringInit {  
    public static void main(String[] args) {  
        String str = "I like";//---------1--------  
        System.out.println(System.identityHashCode(str));//内存地址hash值
        str = str + "java";//--------2---------  
        System.out.println(System.identityHashCode(str));  
    }  
}

该程序输出:

14576877

12677476

说明:str似乎是变了,这是为什么呢?其实是这样的:str只是一个引用变量,当程序执行完1后,str指向“I like”。当程序执行完2之后,连接运算符会将两个字符串连在一起,并且让str指向新的串:"I like java",所以,从这里应该可以看得出来,最初的对象确实没有改变,只是str所指向的对象在不断改变。

1.2 常用的构造方法

String对象的另一种初始化方式,就是采用String类提供的构造方法进行初始化。

其中String类提供了16种构造方法,常用的有五种:

String() --------- 初始化一个String对象,表示一个空字符序列

String(String value) --------- 利用一个直接量创建一个新串

String(char[] value) --------- 利用一个字符数组创建

String(char[] value,int offset,int count) --------- 截取字符数组,从offset开始count个字符创建

String(StringBuffer buffer) --------- 利用StringBuffer创建

 

2String类的一些常用方法

2.1 public int length()

该方法用于获取字符串长度。

实现代码:

public int length() {  
    return count;  
}

这是JDK中的原始实现,countString类里被定义为一个整型常量:private final int count;并且不论采用哪种构造方法,最终都会为count赋值。

2.2 public boolean equals(Object anObject)

该方法用于比较字符串对象是否相等。

实现代码

public boolean equals(Object anObject) {  
    if (this == anObject) {  
        return true;  
    }  
    if (anObject instanceof String) {  
        String anotherString = (String)anObject;  
        int n = count;  
        if (n == anotherString.count) {  
            char v1[] = value;  //---------1---------  
            char v2[] = anotherString.value;//-------2----------  
            int i = offset;  
            int j = anotherString.offset;  
            while (n-- != 0) {  
                if (v1[i++] != v2[j++])  
                return false;  
            }  
            return true;  
        }  
    }  
    return false;  
}

12处也看出来,String的底层是基于字符数组的。我们可以像下面这种方式使用equals()

String s1 = new String("hello world");  
String s2 = new String("hello world");  
String s3 = new String("hello");  
System.out.println(s1.equals(s2));;  
System.out.println(s1.equals(s3));

结果输出:

true

false

此处插入一个很重要的知识点,重写equals()的一般步骤及注意事项

1. 使用==操作符检查“实参是否为指向对象的一个引用”。

2. 使用instanceof操作符检查“实参是否为正确的类型”。

3. 把实参转换到正确的类型。

4. 对于该类中每一个“关键”域,检查实参中的域与当前对象中对应的域值是否匹配。

a.对于既不是float也不是double类型的基本类型的域,可以使用==操作符进行比较

b.对于对象引用类型的域,可以递归地调用所引用的对象的equals方法

c.对于float类型的域,先使用Float.floatToIntBits转换成int类型的值,然后使用==操作符比较int类型的值

d.对于double类型的域,先使用Double.doubleToLongBits转换成long类型的值,然后使用==操作符比较long类型的值。

5. 当你编写完成了equals方法之后,应该问自己三个问题:它是否是对称的、传递的、一致的?(其他两个特性通常会自行满足)    如果答案是否定的,那么请找到这些特性未能满足的原因,再修改equals方法的代码。

先看如下示例:

public class StringInit {  
    public static void main(String[] args) {  
        String s = "hello world";  
        String s1 = new String("hello world");  
        String s2 = new String("hello world");  
        String s3 = new String("hello");  
        String s4 = "hello world";  
          
        System.out.println(s.equals(s1));;  
        System.out.println(s1.equals(s2));  
        System.out.println(s1.equals(s3));  
        System.out.println("------------------");  
        System.out.println(s == s1);  
        System.out.println(s == s3);  
        System.out.println(s == s4);  
    }  
}

输出:

true

true

false

------------------

false

false

true

此处验证了一个问题,就是比较方法equals()==的区别,一句话:equals()比较的是对象的内容,也就是JVM堆内存中的内容,==比较的是地址,也就是栈内存中的内容。

注意:此处隐藏着一个比较细的编程习惯,尤其是用==进行比较的时候,尽量将常量放在==的左边,因为我们有的时候,会不小心将==写成=,这样的话,如果将常量放在左边,编译器会报错,提醒你,但是,如果将变量放在左边,常量放右边,即使你写成了=,编译器默认为变量赋值了,因此也不会报错。

 

2.3 public int compareTo(String anotherString)

因为String类实现了public interface Comparable<T>,而Comparable接口里有唯一的方法:public int compareTo(T o)。所以,String类还有另一个字符串比较方法:compareTo()

实现代码:

public int compareTo(String anotherString) {  
 int len1 = count;  
    int len2 = anotherString.count;  
    int n = Math.min(len1, len2);  
    char v1[] = value;  
    char v2[] = anotherString.value;  
    int i = offset;  
    int j = anotherString.offset;  
 
    if (i == j) {  
        int k = i;  
        int lim = n + i;  
        while (k < lim) {  
            char c1 = v1[k];  
            char c2 = v2[k];  
            if (c1 != c2) {  
                return c1 - c2;  
            }  
            k++;  
        }  
    } else {  
        while (n-- != 0) {  
            char c1 = v1[i++];  
            char c2 = v2[j++];  
            if (c1 != c2) {  
                return c1 - c2;  
            }  
        }  
    }  
    return len1 - len2;  
}

Compare首先会对字符串左对齐,然后从左到右依次比较。如果遇到不同,则返回该两个不同字符ASCII值差,如果比较结束,则返回两个字符串长度差。

 

2.4 public char charAt(int index)

该方法用于获取获取指定位置的字符。

实现代码:

public char charAt(int index) {  
    if ((index < 0) || (index >= count)) {  
        throw new StringIndexOutOfBoundsException(index);  
    }  
    return value[index + offset];  
}

2.5 public String substring(int beginIndex)

该方法用于截取字符串

实现代码:

public String substring(int beginIndex) {  
    return substring(beginIndex, count);  
}  
public String substring(int beginIndex, int endIndex) {  
    if (beginIndex < 0) {  
        throw new StringIndexOutOfBoundsException(beginIndex);  
    }  
    if (endIndex > count) {  
        throw new StringIndexOutOfBoundsException(endIndex);  
    }  
    if (beginIndex > endIndex) {  
        throw new StringIndexOutOfBoundsException(endIndex - beginIndex);  
    }  
    return ((beginIndex == 0) && (endIndex == count)) ? this :  
        new String(offset + beginIndex, endIndex - beginIndex, value);  
}

示例:

public class CompareToTest {  
    public static void main(String[] args) {  
        String s = "helloworld";  
        String s1 = s.substring(2);  
        String s2 = s.substring(2, 7);  
        String s3 = (String) s.subSequence(2, 7);  
        System.out.print("s1:"+s1+"\n"+"s2:"+s2+"\n"+"s3:"+s3);  
    }  
}

输出:

s1:lloworld

s2:llowo

s3:llowo

该类里面包含一个subSequence()方法,该方法与substring(int,int)返回的结果一样,观察下源码,不难发现的区别:

public CharSequence subSequence(int beginIndex, int endIndex) {  
     return this.substring(beginIndex, endIndex);  
}

其实subSequence()内部就是调用的substring(beginIndex, endIndex),只是返回值不同。

subString返回的是StringsubSequence返回的是实现了CharSequence接口的类,也就是说使用subSequence得到的结果,只能使用CharSequence接口中的方法。不过在String类中已经重写了subSequence,调用subSequence方法,可以直接转为String对象,如我们例子中的做法。

 

2.6 public String replace(char oldChar, char newChar)public String replaceAll(String regex, String replacement)

实现代码:

public String replace(char oldChar, char newChar) {  
    if (oldChar != newChar) {  
        int len = count;  
        int i = -1;  
        char[] val = value; /* avoid getfield opcode */  
        int off = offset;   /* avoid getfield opcode */  
  
        while (++i < len) {  
            if (val[off + i] == oldChar) {  
                break;  
            }  
        }  
        if (i < len) {  
        char buf[] = new char[len];  
        for (int j = 0 ; j < i ; j++) {  
            buf[j] = val[off+j];  
        }  
        while (i < len) {  
            char c = val[off + i];  
            buf[i] = (c == oldChar) ? newChar : c;  
            i++;  
        }  
        return new String(0, len, buf);  
        }  
    }  
    return this;  
}  
public String replaceAll(String regex, String replacement) {  
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);  
}

前者参数为两个字符,用newChar替换原串里的所有oldChar

后者从第一个参数可以看出,需要替换的东西可以用正则表达式描述。例子如下:

public class ReplaceTest {  
    public static void main(String[] args) {  
        String s = "hello world";  
        String s1 = s.replace("l", "d");  
        System.out.println(s1);  
        String s2 = "a78e5opx587";  
        String s3 = s2.replaceAll("[0-9]", "");//用空串替换原串里所有的0-9的数字  
        System.out.println(s3);  
    }  
}

输出:

heddo wordd

aeopx

 

2.7 public String[] split(String regex)

该方法用于分割字符串,得到一个String类型的数组,根据regex可知,参数是个正则表达式。示例如下:

public class SpiltTest {  
    public static void main(String[] args) {  
        String s = "hello world";  
        String s1 = "hello.worldd";  
        String[] s2 = s.split(" ");  
        String[] s3 = s1.split("\\.");  
        for(int i=0; i<s2.length; i++){  
            System.out.print(s2[i]+" ");  
        }  
        System.out.println();  
        for(int j=0; j<s3.length; j++){  
            System.out.print(s3[j]+" ");  
        }  
    }  
}

输出:

hello world

hello worldd

关于spilt()的其他重载方法,可参见JDKString类的实现。

spilt()需要注意的事项,就是当分隔符为 . 的话,处理起来不一样,必须写成\\.因为.是正则表达式里的一个特殊符号,必须进行转义

 

2.8 public native String intern()

intern()方法和前面说的equals()方法关系密切,从public native String intern()看出,它是Java的本地方法,我们先来看看Java文档里的描述:

Returns a canonical representation for the string object.  
A pool of strings, initially empty, is maintained privately by the  
class String.When the intern method is invoked, if the pool already contains a  
string equal to this String object as determined by  
theequals(Object) method, then the string from the pool is  
returned. Otherwise, this String object is added to the  
pool and a reference to this String object is returned.  
It follows that for any two strings s and t,  
s.intern()==t.intern() is true if and only if s.equals(t) is true.  
All literal strings and string-valued constant expressions are interned.   
@return  a string that has the same contents as this string, but is  
guaranteed to be from a pool of unique strings.

意思就是说,返回字符串一个规范的表示。进一步解释:有两个字符串sts.equals(t),s.intern()==t.intern().举个例子:

public class StringTest {  
    public static void main(String[] args) {  
        String s = new String("abc");  
        String s1 = "abc";  
        String s2 = "abc";  
        String s3 = s.intern();  
        System.out.println(s == s1);//false  
        System.out.println(s == s2);//false  
        System.out.println(s == s3);//false  
        System.out.println(s1 == s3);//true        
    }  
}

输出结果如注释所示,前两个结果前面已经说的很清楚了,现在拿最后一个说明,首先看看s3 = s.intern()这句,当调用s.intern()这句的时候,先去字符串常量池中找,是否有abc这个串,如果没有,则新增,同时返回引用,如果有,则返回已经存在的引用,此处s1s2都指向常量池中的abc对象,所以此处是存在的,调用s.intern()后,s3s1s2指向同一个对象,所以s1==s3返回的是true

intern()做到了一个很不寻常的行为:在运行期动态的在方法区创建对象,一般只有像new关键字可以在运行期在堆上面创建对象,所以此处比较特殊。属于及时编译的概念。

一般常见的字符串处理函数就这些,其它的还有很多,就不一一列举。

 

3、一些常见的问题,处理结果

3.1 String s = "123" + "456"内存中产生几个字符串对象?

这是个比较有争议的问题,面试的时候,老师还挺喜欢问,论坛上大家说几个的也有,我给大家分析一下,因为我们前面有提到Java字符串的缓存机制,编译器在编译的时候会进行优化,所以在编译的过程中123456被合成了一个字符串"123456",因此,如果缓存池中目前没有123456这个对象,那么会产生一个,即""123456",且栈中产生一个引用s指向它,如果缓存池中已经存在"123456",那么将产生0个对象,直接用s指向它。

3.2 如果spilt()函数的参数在要分割的字符串中没有怎么办?如String s = "helloworld" ,我现在调用String[] s2 = s.spilt("abc"),返回什么?

代码如下:

public class StringSpilt {  
    public static void main(String[] args) {  
        String s = "helloworld";  
        String[] s2 = s.split("abc");  
        for (int i = 0; i < s2.length; i++) {  
            System.out.println(s2[i]);  
        }  
    }  
}

输出结果:helloworld

说明当遇到源字符串中没有的字符时,会把它整个串放入到数组中。   

3.3 关于字符串自动类型转换分析

首先看一下题的类型:

int i = 2;  
int j = 3;  
String s = "9";  
System.out.println(i+j+s);        
System.out.println("-----------------------");  
System.out.println(i+s+j);

输出:

59

-----------------------

293

首先i+j=5,然后59自然连接,这里涉及到java的自动类型转换,此处int型的直接转成String类型的。第二个依次连接,都转化为String类型的了。

public class Main {
    public static void main(String[] args) {
       String s = "ab";  
       String s1 = "a";  
       String s2 = s1 + "b";  
       String s3 = "ab";   
       System.out.println(s == s2);//false  
       System.out.println(s2 == s3);//false  
       System.out.println(s2.hashCode() == s3.hashCode());  //true
       System.out.println(System.identityHashCode(s2) == System.identityHashCode(s3));  //false
       String s4 = "ad";  
       String s5 = "a" + "d";  
       String s6 = "ad";  
       System.out.println(s4 == s5);//true  
       System.out.println(s4 == s6);//true
 
    }
}

此处主要是想说明:s1+"b""a"+"b"的不同,再看一段代码:

System.out.println(s1.hashCode());  
System.out.println(s2.hashCode());  
System.out.println(s3.hashCode());  
System.out.println(s4.hashCode());  
System.out.println(s5.hashCode());

输出:

97

3105

3105

3107

3107

说明s1+"b"的过程创建了新的对象,所以地址不一样了。所以用==比较的话,返回的是false

此处继续补充:为什么s1+"b"会产生新的对象?而没有去常量池查找是否已经存在ab对象,以致于s==s2返回false。因为我们说过常量池(下文会讲常量池)是在编译期确定好的,所以如果我们的语句时String s5 = "ab"的话,这个是在编译期确定的,会去常量池查找,而此处我们的语句时s2 = s1+"b"s2的值只有在运行期才能确定,所以不会去常量池查找,也就是产生新串。再次提问:那么这里s2的值是在哪儿分配的呢?堆、JVM栈还是运行时常量池?正确回答:s2在堆上分配,因为+的内部实现是用StringBuilder来实现的。String s2 = s1+"b" 内部是这样实现的:String s2 = new StringBuilder(s1).append("b").toString();所以是在堆上来分配的

此处网友cowmich补充:调用s2.hashCode() == s3.hashCode()返回true。我解释下:

==比较的是他们的地址,s1+"b"会产生一个新的串,所以和ss2==比,返回false,如果用equals的话,返回肯定是true,因为equals()比较的是对象的内容(String类是这样的)。至于hashCode,是这样的:如果没有重写ObjecthashCode(),那么如果对象调用equals()放回true,则这两个对象调用hashCode()后返回的整数一定相等。此处继续补充:对于Object类而言,原生的equals()方法,必须两个对象的地址和内容都一样才返回true,同时Object类原生的hashCode()是参照对象的地址和内容根据一定的算法生产的。所以原生的hashCode()只有调用equals()返回true才相等。而String类不同,String类重写了Objectequals(),放松了条件,只要对象地址或者内容相等就返回true,我们看看源码:

public boolean equals(Object anObject) {  
    if (this == anObject) {  
        return true;  
    }  
    if (anObject instanceof String) {  
        String anotherString = (String)anObject;  
        int n = count;  
        if (n == anotherString.count) {  
        char v1[] = value;  
        char v2[] = anotherString.value;  
        int i = offset;  
        int j = anotherString.offset;  
        while (n-- != 0) {  
            if (v1[i++] != v2[j++])  
            return false;  
        }  
        return true;  
        }  
    }  
    return false;  
}

同时,String类重写了hashCode()方法,只要内容相等,则调用hashCode返回的整数值也相等,所以此处:s3s2虽然地址不等,但是内容相等,所以会有:s2.hashCode() == s3.hashCode()返回true。但是这句话反过来讲就不一定成立了,因为毕竟hashCode()只是一种算法。继续补充:刚刚说了Object类和String类,此处补充下Integer类:Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer a=new Integer(50),a.hashCode的值就是50 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。

关于常量池、字符串常量池、运行时常量池的介绍:

常量池一般就是指字符串常量池,是用来做字符串缓存的一种机制,当我们在程序中写了形如String s = "abc"这样的语句后,JVM会在栈上为我们分配空间,存放变量s和对象”abc“,当我们再次需要abc对象时,如果我们写下:String s1 = "abc"的语句时,JVM会先去常量池中找,如果不存在,则新创建一个对象。如果存在,则直接将s1指向之前的对象”abc“,此时,如果我们用==来判断的话,返回的true。这样做的好处就是节省内存,系统响应的速度加快,(因为省去了对象的创建时间)这也是缓存系统存在的原因。常量池是针对在编译期间就确定下来的常量而言的,如上所说的String类的一些对象。但是,当类被加载后,常量池会被搬到方法区的运行时常量池,此时就不再是静态的了,那么是不是就不能向常量池中添加新的内容了呢(因为我们刚刚说过,常量池是在编译期确定好的)?答案是否定的,我们依然可以在运行时向常量池添加内容!这就是我们说过的String类有个方法叫intern(),它可以在运行时将新的常量放于常量池。因为我在上文中已经详细介绍过intern(),此处不再赘述!

 

二、StringBufferStringBuilder

1、初始化

StringBufferStringBuilder就是所谓的可变字符串类,共四个构造方法:

StringBuffer()

public StringBuffer(int paramInt)

public StringBuffer(String paramString)

public StringBuffer(CharSequence paramCharSequence)

观察其源码发现,使用StringBuffer()时,默认开辟16个字符的长度的空间,使用public StringBuffer(int paramInt)时开辟指定大小的空间,使用public StringBuffer(String paramString)时,开辟paramString.length+16大小的空间。都是调用父类的构造器super()来开辟内存。这方面StringBufferStringBuilder都一样,且都实现AbstractStringBuilder类。

2、主要方法

二者几乎没什么区别,基本都是在调用父类的各个方法,一个重要的区别就是StringBuffer是线程安全的,内部的大多数方法前面都有关键字synchronized,这样就会有一定的性能消耗,StringBuilder是非线程安全的,所以效率要高些。

public class Main {
    public static void main(String[] args) throws Exception {  
       String string = "0";  
       int n = 10000;  
       long begin = System.currentTimeMillis();  
       for (int i = 1; i < n; i++) {  
           string += i;  
       }  
       long end = System.currentTimeMillis();  
       long between = end - begin;  
       System.out.println("使用String类耗时:" + between+"ms");  
 
       int n1 = 10000;  
       StringBuffer sb = new StringBuffer("0");  
       long begin1 = System.currentTimeMillis();  
       for (int j = 1; j < n1; j++) {  
           sb.append(j);  
       }  
       long end1 = System.currentTimeMillis();  
       long between1 = end1 - begin1;  
       System.out.println("使用StringBuffer类耗时:" + between1+"ms");  
 
       int n2 = 10000;  
       StringBuilder sb2 = new StringBuilder("0");  
       long begin2 = System.currentTimeMillis();  
       for (int k = 1; k < n2; k++) {  
           sb2.append(k);  
       }  
       long end2 = System.currentTimeMillis();  
       long between2 = end2 - begin2;  
       System.out.println("使用StringBuilder类耗时:" + between2+"ms");  
    }  
}

输出:
使用String类耗时:317ms

使用StringBuffer类耗时:5ms

使用StringBuilder类耗时:1ms

虽然这个数字每次执行都不一样,而且每个机子的情况也不一样,但是有几点是确定的,String类时间消耗的明显比另外两个多得多,StringBuffer要比StringBuilder消耗的多。

2.1 public synchronized int length() public synchronized int capacity()

获取当前字符串的长度,获取当前缓冲区的大小。

StringBuffer sb = new StringBuffer();  
System.out.println(sb.length());;  
System.out.println(sb.capacity());

输出:

0

16

StringBuffer sb = new StringBuffer("hello");  
System.out.println(sb.length());;  
System.out.println(sb.capacity());

输出:

5

21


2.2 public boolean equals(Object paramObject)

示例:

StringBuffer sb = new StringBuffer("hello");  
StringBuffer sb2 = new StringBuffer("hello");  
System.out.println(sb.equals(sb2));

以上程序输出false,是不是有点惊讶?记得之前我们的文章说过,equals()比较的是字符串的内容,按理说此处应该输出的是true才对。

究其原因,String类重写了Objectequals(),所以只需要看内容是否相等即可,但是StringBuffer没有重写equals(),此处的equals()仍然是调用的Object类的,所以,调用StringBuffer类的equals(),只有地址和内容都相等的字符串,结果才会返回true

另外StringBuffer有一系列追加、插入、删除字符串的方法,首先append(),就是在原来的字符串后面直接追加一个新的串,和String类相比有明显的好处:

String类在追加的时候,源字符串不变(这就是为什么说String是不可变的字符串类型),和新串连接后,重新开辟一个内存。这样就会造成每次连接一个新串后,都会让之前的串报废,因此也造成了不可避免的内存泄露。

操作示例:

//append()  
StringBuffer sb = new StringBuffer("helloworld, ");  
sb.append("I'm ").append("erqing ").append("who ").append("are you ?");  
System.out.println(sb);  
//public synchronized StringBuffer insert(int paramInt, Object paramObject)  
sb.insert(12, /*9*/"nice! ");  
System.out.println(sb);  
//public synchronized StringBuffer reverse()  
sb.reverse();  
System.out.println(sb);  
sb.reverse();  
System.out.println(sb);  
//public synchronized StringBuffer delete(int paramInt1, int paramInt2)  
//public synchronized StringBuffer deleteCharAt(int paramInt)  
sb.delete(12, 18);  
System.out.println(sb);  
sb.deleteCharAt(5);  
System.out.println(sb);

输出:

helloworld, I'm erqing who are you ?

helloworld, nice! I'm erqing who are you ?

? uoy era ohw gniqre m'I !ecin ,dlrowolleh

helloworld, nice! I'm erqing who are you ?

helloworld, I'm erqing who are you ?

helloorld, I'm erqing who are you ?

 

2.3 public synchronized void trimToSize()

该方法用于将多余的缓冲区空间释放出来。

StringBuffer sb = new StringBuffer("hello erqing");  
System.out.println("length:"+sb.length());  
System.out.println("capacity:"+sb.capacity());  
sb.trimToSize();  
System.out.println("trimTosize:"+sb.capacity());

输出:

length:12

capacity:28

trimTosize:12

 

三、字符串处理类StringTokenizer

StringTokenizerjava.util包下的一个类,用来对字符串做简单的处理。

String s = "Tonight is the answer !";  
StringTokenizer st = new StringTokenizer(s," ");  
int count = st.countTokens();  
System.out.println("个数为:"+count);  
while (st.hasMoreTokens()) {  
String token = st.nextToken();  
System.out.println(token);

输出:

个数为:5

Tonight

is

the

answer

!

 

本章节一轮学习结束。

(本博文为学习【从菜鸟到高手演变】系列博客http://blog.csdn.net/zhangerqing 所作笔记。感谢原作者!!!)

 

 

你可能感兴趣的文章

评论区

发表评论

必填

选填

选填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

您好,欢迎到访网站!
  查看权限

«   2018年10月   »
1234567
891011121314
15161718192021
22232425262728
293031

最新留言