Java中的String类——特殊类的存在

学习Java中......    总结一下特殊的String类

1.Java中String类的一个简单总结

不像C/ C++,字符串只是一个char数组,Java字符串是Java .lang类的对象。

java 中的String和传统的Class类一样:

  • Sting和双引号形式的字符串常量(例如“hello world”)相关联,不需要调用构造器创建String实例对象,而可以直接将字符串常量赋值给字符串变量。
  • 重载操作符“+”可以连接两个字符串操作数,但是不可以作用于其他任何对象。
  • 字符串是不能变的,也就是一旦创建了字符串的内容,其内容就不能再被更改。例如构造方法toUpperCase(),它是重新返回了一个新的字符串,而不是对内容进行修改。

下面是String的常用方法(参见JDK API中java.lang.String的详细列表):

// Length
int length()       // returns the length of the String
boolean isEmpty()  // same as thisString.length == 0
 
// Comparison
boolean equals(String another) // CANNOT use '==' or '!=' to compare two Strings in Java
boolean equalsIgnoreCase(String another)
int compareTo(String another)  // return 0 if this string is the same as another;
                               // <0 if lexicographically less than another; or >0
int compareToIgnoreCase(String another)
boolean startsWith(String another)
boolean startsWith(String another, int fromIndex)  // search begins at fromIndex
boolean endsWith(String another)
 
// Searching & Indexing
int indexOf(String search)
int indexOf(String search, int fromIndex)
int indexOf(int character)
int indexOf(int character, int fromIndex)      // search forward starting at fromIndex
int lastIndexOf(String search)
int lastIndexOf(String search, int fromIndex)  // search backward starting at fromIndex
int lastIndexOf(int character)
int lastIndexOf(int character, int fromIndex)
 
// Extracting a char or part of the String (substring)
char charAt(int index)              // index from 0 to String's length - 1
String substring(int fromIndex)
String substring(int fromIndex, int endIndex)  // exclude endIndex
 
// Creating a new String or char[] from the original (Strings are immutable!)
String toLowerCase()
String toUpperCase()
String trim()          // create a new String removing white spaces from front and back
String replace(char oldChar, char newChar)  // create a new String with oldChar replaced by newChar
String concat(String another)               // same as thisString + another
char[] toCharArray()                        // create a char[] from this string
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)  // copy into dst char[]
 
// Static methods for converting primitives to String
static String ValueOf(type arg)  // type can be primitives or char[]
 
// Static method resulted in a formatted String using format specifiers
static String format(String formattingString, Object... args)   // same as printf()
 
// Regular Expression (JDK 1.4)
boolean matches(String regexe)
String replaceAll(String regexe, String replacement)
String replaceAll(String regexe, String replacement)
String[] split(String regexe)             // Split the String using regexe as delimiter,
                                          // return a String array
String[] split(String regexe, int count)  // for count times only

静态方法String.format( )  JDK 1.5:

静态方法String.format( ) (在JDK 1.5中引入) ,可以使用像C语言中printf( )的格式说明符一样,生成格式化字符串。format()方法的形式与printf( )相同。例如:

String.format("%.1f", 1.234);   // returns String "1.2"  

如果你需要生成一个格式化的字符串,String.format( ) 非常有用。对于复杂的字符串,使用带有格式标示符的StringBuffer或StringBuilder。如果只需要将一个简单的格式化字符串打印到控制台,直接使用System.out.printf( )就可以了,例如:

System.out.printf("%.1f", 1.234);

2.String类的特殊之处

由于String在程序中使用非常频繁(据说使用率有20%左右),因此在java中对String做了特殊处理。

Java的设计者决定在面向对象的语言中保留基本类型,而不是把所有东西都变成对象,从而提高语言的性能。基本类型存储在调用堆栈中,这需要更少的存储空间,而且操作成本更低。另一方面,对象存储在程序堆中,这需要复杂的内存管理和更多的存储空间。出于性能原因,Java中的String被设计为介于基本类型和类之间。String的特殊功能包括:

  • 用于对基本类型(如int和double)执行加法的“+”操作符,被重载以操作字符串对象。'+'对两个字符串操作数进行拼接。【Java不支持出于软件工程考虑的操作符重载。在像c++这样支持操作符重载的语言中,你是可以使用“+”操作符执行减法,这导致了糟糕的代码。在Java中,“+”操作符是唯一内部重载以支持字符串连接的操作符。】
  • 字符串可以由一下两种方法构造:

           直接将字符串常量赋值给字符串变量——就像基本类型一样;

           通过“new”的方式创建,类似于其他类,然而,这种方法并不常用,也不推荐使用。

           举例:

String str1 = "Java is Hot";           // Implicit construction via string literal
String str2 = new String("I'm cool");  // Explicit construction via new
  • 字符串常量存储在公共池(a common pool)中,这有助于共享具有相同内容的字符串的存储,以节省存储空间。通过new操作符分配的字符串对象存储在堆中,对于相同的内容没有共享存储。

2.1  String常量 vs. String 字符串

如前所述,构造字符串有两种方法:通过指定字符串文字的隐式构造,或者通过新的操作符和构造函数显式创建字符串对象。例如

String s1 = "Hello";              // String literal
String s2 = "Hello";              // String literal
String s3 = s1;                   // same reference
String s4 = new String("Hello");  // String object
String s5 = new String("Hello");  // String object

Java提供了一种特殊的机制来保存字符串常量在字符串公共池中。如果两个字符串文字具有相同的内容,它们将在公共池中共享相同的存储。这种方法用于为经常使用的字符串节省存储空间。另一方面,通过新操作符和构造函数创建的字符串对象保存在堆中。堆中的每个字符串对象都有自己的存储,就像其他任何对象一样。即使两个字符串对象具有相同的内容,也不能共享堆中的存储。

你可以使用String类的equals()方法来比较两个字符串的内容。可以使用 ' == ' 来比较两个对象的引用(或指针)。

s1 == s1;         // true, same pointer
s1 == s2;         // true, s1 and s1 share storage in common pool
s1 == s3;         // true, s3 is assigned same pointer as s1
s1.equals(s3);    // true, same contents
s1 == s4;         // false, different pointers
s1.equals(s4);    // true, same contents
s4 == s5;         // false, different pointers in heap
s4.equals(s5);    // true, same contents

注意:

  • 在上面的例子中,使用 ' == ' 来比较两个字符串对象的引用。这样做是为了演示在公共池中共享存储的字符串文本与在堆中创建的字符串对象之间的区别,在程序中使用(str1 == str2)比较两个String的内容是一个逻辑错误的。
  • 可以通过直接赋值共享在公共池中的字符串常量来创建,通常不建议使用新的操作符在堆中构造字符串对象。

2.2  String is Immutable

由于具有相同内容的字符串文本共享公共池中的存储,所以Java的字符串被设计为不可变的。也就是说,一旦构造了字符串,就不能修改它的内容。否则,共享相同存储位置的其他字符串引用将受到更改的影响。诸如toUpperCase()之类的方法可能会修改字符串对象的内容,实际上,它是创建了一个全新的String对象并返回给调用者,一旦没有更多引用,就会释放原始字符串对象,然后进行垃圾回收。因为字符串是不可变的,如果你需要经常修改字符串(这会创建许多占用新存储区域的新字符串),那么使用字符串是没有效率可言的。例如

// inefficient codes
String str = "Hello";
for (int i = 1; i < 1000; ++i) {
   str = str + i;
}

如果必须经常修改字符串的内容,则使用StringBuffer或StringBuilder类。

3.  StringBuffer & StringBuilder

JDK提供了两个类来支持可变字符串:StringBuffer和StringBuilder(在核心包java.lang中)。StringBuffer或StringBuilder对象和普通对象一样,都存储在堆中而不是共享的,因此可以修改它们从而不会对其他对象造成不利的副作用。

StringBuilder类是在JDK 1.5中引入的。它与StringBuffer类相同,只是StringBuilder对于多线程操作不同步synchronized。但是,对于单线程程序,StringBuilder没有同步开销,效率更高。

3.1  java.lang.StringBuffer

// Constructors
StringBuffer()             // an initially-empty StringBuffer
StringBuffer(int size)     // with the specified initial size
StringBuffer(String s)     // with the specified initial content
 
// Length
int length()
 
// Methods for building up the content
StringBuffer append(type arg)  // type could be primitives, char[], String, StringBuffer, etc
StringBuffer insert(int offset, arg)
 
// Methods for manipulating the content
StringBuffer delete(int start, int end)
StringBuffer deleteCharAt(int index)
void setLength(int newSize)
void setCharAt(int index, char newChar)
StringBuffer replace(int start, int end, String s)
StringBuffer reverse()
 
// Methods for extracting whole/part of the content
char charAt(int index)
String substring(int start)
String substring(int start, int end)
String toString()
 
// Methods for searching
int indexOf(String searchKey)
int indexOf(String searchKey, int fromIndex)
int lastIndexOf(String searchKey)
int lastIndexOf(String searchKey, int fromIndex)

/*Take note that StringBuffer is an ordinary object. You need to use a constructor to create a StringBuffer (instead of assigning to a String literal). Furthermore, '+' operator does not apply to objects, including the StringBuffer. You need to use a proper method such as append() or insert() to manipulating a StringBuffer.*/

/*To create a string from parts, It is more efficient to use StringBuffer (multi-thread) or StringBuilder (single-thread) instead of via String concatenation. For example,*/
// Create a string of YYYY-MM-DD HH:MM:SS
int year = 2010, month = 10, day = 10;
int hour = 10, minute = 10, second = 10;
String dateStr = new StringBuilder()
      .append(year).append("-").append(month).append("-").append(day).append(" ")
      .append(hour).append(":").append(minute).append(":").append(second).toString();
System.out.println(dateStr);
   
// StringBuilder is more efficient than String concatenation
String anotherDataStr = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
System.out.println(anotherDataStr);

JDK编译器实际上使用String和StringBuffer通过“+”操作符处理字符串连接。例如:

String msg = "a" + "b" + "c";

被编译为一下代码来提高效率:

String msg = new StringBuffer().append("a").append("b").append("c").toString();

3.2  java.lang.StringBuilder (JDK 1.5)

JDK 1.5引入了一个新的StringBuilder类(在包java.lang中),它与StringBuffer类几乎相同,只是没有同步。换句话说,如果多个线程同时访问一个StringBuilder实例,就不能保证它的完整性。然而,对于一个单线程程序(最常见的),取消同步的开销会使StringBuilder更快。

StringBuilder与StringBuffer类API兼容,即具有相同的构造函数和方法集,但不能保证同步。StringBuilder可以在单线程环境下替代StringBuffer。

3.3  Benchmarking String/StringBuffer/StringBuilder

下面的程序比较了通过string对象和StringBuffer反转长字符串所花费的时间。

// Reversing a long String via a String vs. a StringBuffer
public class StringsBenchMark {
   public static void main(String[] args) {
      long beginTime, elapsedTime;
 
      // Build a long string
      String str = "";
      int size = 16536;
      char ch = 'a';
      beginTime = System.nanoTime();   // Reference time in nanoseconds
      for (int count = 0; count < size; ++count) {
         str += ch;
         ++ch;
         if (ch > 'z') {
            ch = 'a';
         }
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " usec (Build String)");
 
      // Reverse a String by building another String character-by-character in the reverse order
      String strReverse = "";
      beginTime = System.nanoTime();
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         strReverse += str.charAt(pos);   // Concatenate
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " usec (Using String to reverse)");
 
      // Reverse a String via an empty StringBuffer by appending characters in the reverse order
      beginTime = System.nanoTime();
      StringBuffer sBufferReverse = new StringBuffer(size);
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         sBufferReverse.append(str.charAt(pos));      // append
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " usec (Using StringBuffer to reverse)");
 
      // Reverse a String by creating a StringBuffer with the given String and invoke its reverse()
      beginTime = System.nanoTime();
      StringBuffer sBufferReverseMethod = new StringBuffer(str);
      sBufferReverseMethod.reverse();     // use reverse() method
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " usec (Using StringBuffer's reverse() method)");
 
      // Reverse a String via an empty StringBuilder by appending characters in the reverse order
      beginTime = System.nanoTime();
      StringBuilder sBuilderReverse = new StringBuilder(size);
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         sBuilderReverse.append(str.charAt(pos));
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " usec (Using StringBuilder to reverse)");
 
      // Reverse a String by creating a StringBuilder with the given String and invoke its reverse()
      beginTime = System.nanoTime();
      StringBuffer sBuilderReverseMethod = new StringBuffer(str);
      sBuilderReverseMethod.reverse();
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " usec (Using StringBuidler's reverse() method)");
   }
}
Elapsed Time is 332100 usec (Build String)
Elapsed Time is 346639 usec (Using String to reverse)
Elapsed Time is 2028 usec   (Using StringBuffer to reverse)
Elapsed Time is 847 usec    (Using StringBuffer's reverse() method)
Elapsed Time is 1092 usec   (Using StringBuilder to reverse)
Elapsed Time is 836 usec    (Using StringBuidler's reverse() method)

观察StringBuilder比StringBuffer快2倍,比String快300倍。reverse()方法是最快的方法,它为StringBuilder和StringBuffer花费了大约相同的时间。

通常,您需要将一行文本分成由空格分隔的标记。java.util。StringTokenizer类支持这一点。<br><div class="br-height"></div>例如,下面的程序反转字符串中的单词。

4.  java.util.StringTokenizer

常见的,你需要将一行文本分成由空格分隔的标记。java.util.StringTokenizer类支持这一点。例如,下面的程序反转字符串中的单词。

// Reverse the words in a String using StringTokenizer
import java.util.StringTokenizer;
public class StringTokenizerTest {
   public static void main(String[] args) {
      String str = "Monday Tuesday Wednesday Thursday Friday Saturday Sunday";
      String strReverse;
      StringBuilder sb = new StringBuilder();
      StringTokenizer st = new StringTokenizer(str);
   
      while (st.hasMoreTokens()) {
         sb.insert(0, st.nextToken());
         if (st.hasMoreTokens()) {
            sb.insert(0, " ");
         }
      }
      strReverse = sb.toString();
      System.out.println(strReverse);
   }
}
// Constructors
StringTokenizer(String s)  // Constructs a StringTokenizer for the given string,
                           // using the default delimiter set of " \t\n\r\f"
                           // (i.e., blank, tab, newline, carriage-return, and form-feed).
                           // Delimiter characters themselves will not be treated as tokens. 
StrintTokenizer(String s, String delimiterSet)  // Use characters in delimiterSet as delimiters.
 
// Methods
boolean hasNextToken()     // Returns true if next token available
String nextToken()         // Returns the next token
 
// Code Sample
StringTokenizer tokenizer = new StringTokenizer(aString);
while (tokenizer.hasNextToken()) {
   String token = tokenizer.nextToken();
   .....
}

JDK文档声明“StringTokenizer是出于兼容性原因而保留的遗留类,在新代码中不鼓励使用它。建议任何寻求此功能的人使用String的split()方法(或java.util.regex包代替。或的东西没看明白怎么用)

例如,下面的程序使用String类的split()方法来反转字符串的单词。


// Reverse the words in a String using split() method of the String class
public class StringSplitTest {
   public static void main(String[] args) {
      String str = "Monday Tuesday Wednesday Thursday Friday Saturday Sunday";
      String[] tokens = str.split("\\s");  // white space '\s' as delimiter
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < tokens.length; ++i) {
         sb.insert(0, tokens[i]);
         if (i < tokens.length - 1) {
            sb.insert(0, " ");
         }
      }
      String strReverse = sb.toString();
      System.out.println(strReverse);
   }
}

Over!完结...

学习内容来自于下面网址:

http://www.ntu.edu.sg/home/ehchua/programming/java/j3d_string.html

 

 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值