欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

深入学习Java编程中的字符串的进阶使用

程序员文章站 2024-03-08 11:11:52
java虽然是在c++基础上发展而来,但却对c++的许多缺陷有所改进,其中一个不得不提的就是字符串,我们知道,随着学习的深入,进入mfc时,当处理字符串或字符时,常会需要通...

java虽然是在c++基础上发展而来,但却对c++的许多缺陷有所改进,其中一个不得不提的就是字符串,我们知道,随着学习的深入,进入mfc时,当处理字符串或字符时,常会需要通过_t()宏将字符或字符串变成unicode型,否则,会在处理中出现bug,而在java中,字符char或存储在character类中的字符,不是一个字节,而是2个字节,采用unicode,这是为了支持全世界上的所有字符。

        字符的序列组成字符串,有两种类型的字符串:一种是创建以后不需要修改的,称为字符串常量,在java中,用string类存储;
     一种是创建以后需要对其进行修改的,称为字符串变量,在java中,用stringbuffer类操作和管理。

 stringbuffer类

1、创建stringbuffer类对象

     stringbuffer类对象表示的是字符串变量(注意是"变量"),每一个stringbuffer类对象都是可以扩充和修改的字符串变量。以下是常用的stringbuffer类构造函数:

      (1)public stringbuffer()

       创建一个新的空的stringbuffer类的对象,其容量初值设置成16个字符(注意是16个字符)

   (2)public stringbuffer(int length)

       创建一个新的空的stringbuffer类的对象,其容量初值设置成length个字符

    (3)public stringbuffer(string str)

       创建一个新的stringbuffer类的对象,其内容为str的内容,容量设置成str长度再加16个字符 (注意:再加上16个字符)


2、stringbuffer类对象的常用方法

     (1)stringbuffer类对象的扩充

         stringbuffer类提供两组方法用来扩充stringbuffer对象所包含的字符,分别是:

        1)public stringbuffer append

                            (object  obj)

          append方法用于扩充stringbuffer对象所包含的字符,该方法将指定的参数对象转化为字符串后,将其附加在原来的stringbuffer对象之后,并返回新的stringbuffer对象。附加的的参数对象可以是各种数据类型的,如int、char、string、double等。

2)public stringbuffer insert(

        int插入位置offset,参数对象类型,参数对象名)

    该方法将指定的参数对象转化为字符串后,将其插入在原来的stringbuffer对象中指定的位置,并返回新的stringbuffer对象。

    (2)stringbuffer类对象的长度与容量

    一个stringbuffer类对象的长度指的是它包含的字符个数;容量指的是被分配的字符空间的数量。

     1)public int length()

        该方法返回当前stringbuffer类对象包含的字符个数。

    2)public int capacity()

   该方法返回当前stringbuffer类对象分配的字符空间的数量。
(3)stringbuffer类对象的修改

   public void setcharat(intindex,charch)

     该方法将当前stringbuffer对象中的index位置的字符替换为指定的字符ch。

    (4)字符串的赋值和加法

      字符串是在程序中要经常使用的数据类型,在java编译系统中引入了字符串的赋值和加法操作。

   (5)其它方法类似string类的方法
3、利用stringtokenizer类分解字符串

stringtokenizer类位于java.util包中, 在使用该类时在程序开始加上

importjava.util.stringtokenizer或

importjava.util.*

stringtokenizer类

对于stringtokenizer类,其主要作用是将字符串按照给定的分割符进行分割,其功能和string类的split方法类似

1、stringtokenizer类的构造函数

(1)stringtokenizer(stringstr)

         为给定的字符串str创建一个stringtokenizer对象,其分隔符默认设置为“\t\n\r\f”,亦即:空格、水平制表符tab、换行、回车、表格符

(2)stringtokenizer(string str,string delim)

              为给定的字符串str创建一个stringtokenizer对象,其分隔符为指定的字符串delim,默认不包含分隔符

 


3)stringtokenizer(string str,string delim,boolean returndelims)

             为给定的字符串str创建一个stringtokenizer对象,其分隔符为指定的字符串delim,如果returndelims为true,则创建的stringtokenizer对象中的每个字符串包含有分隔符,否则不包含分隔符

2、stringtokenizer类的常用方法

nintcounttokens()
返回stringtokenizer对象中被分割后子字符串的个数
nbooleanhasmoreelements()
该方法的功能和hasmoretokens()方法的功能一样
nbooleanhasmoretokens()
检测stringtokenizer对象中是否包含分割好的子字符串,有则返回true,否则返回false
objectnextelement()

该方法具有nexttoken()一样的功能,主要区别是它返回的不是string对象,而是一个object对象

stringnexttoken()

返回stringtokenizer对象中下一个分割好的子字符串

stringnexttoken(string delim)

返回stringtokenizer对象中下一个分割好的子字符串,但是分隔符被重新设定为delim

n其实在有些编程语言中,比如c语言,其字符串就是由字符数组构成的,每个字符串的结尾用“\0”标志,但是在java中却不是这样的。
n在java中,字符串通常是作为string类的对象存在着,如:strings=“i like java!”,其中“ilike java!”就是一个对象。
所以说,java中的字符串和字符数组是完全不相同的,和c语言中的字符串也是不一样的!

 


n为了方便字符串和字符数组的转换,在string类中提供了许多这样的构造函数和方法
n如构造函数string(char[] value)
n方法tochararray()
方法valueof(char[] data)


常量池

对于源程序中出现的字符串常量,当程序运行时,会统一保存到一个常量池中进行缓存。
对引用这些缓存在常量池中的字符串的变量进行比较,用==也会得到正确的结果。

但在运行时,对字符串的各种操作如+、substring等等,都是会产生新的字符串对象的。
但是强大的编译器会对字符串常量的拼接进行优化,诸如s3 = "hell" + "o"时,s3仍然会
指向常量池中的字符串。但对于变量的运算,总不能要求虚拟机执行诸如s1 + s2时还要
判断结果是否已在常量池中了吧。因此,要用equals而非==去判断两个字符串是否相等。

public static void main(string[] args) { 
 
 // string constants are put in constant pool. 
 string s1 = "hello"; 
 string s2 = "hello"; 
 string s3 = "hell" + "o"; 
 system.out.println(s1 == s2); 
 system.out.println(s1 == s3); 
  
 // operation like +,substring on string create new one. 
 string s4 = "hell"; 
 string s5 = s4 + "o"; 
 system.out.println(s1 == s5); 
 system.out.println(s1.equals(s5)); 
  
 // substring has special handle on substring(0) 
 string s6 = s1.substring(0); 
 system.out.println(s1 == s6); 
} 

测试代码s1、s2、s3的字节码:

   0:   ldc     #16; //string hello
   2:   astore_1
   3:   ldc     #16; //string hello
   5:   astore_2
   6:   ldc     #16; //string hello
   8:   astore_3

测试代码s4、s5的字节码:
  
   41:  ldc     #30; //string hell
   43:  astore  4
   45:  new     #32; //class java/lang/stringbuilder
   48:  dup
   49:  aload   4
   51:  invokestatic    #34; //method java/lang/string.valueof:(ljava/lang/object;)ljava/lang/string;
   54:  invokespecial   #40; //method java/lang/stringbuilder."<init>":(ljava/lang/string;)v
   57:  ldc               #43; //string o
   59:  invokevirtual   #45; //method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder;
   62:  invokevirtual   #49; //method java/lang/stringbuilder.tostring:()ljava/lang/string;

注意一点是substring方法,substring(0,3)是得到从字符0到2的字符串。这样设计的原因
也许是这样容易计算子串的长度,3-0=3。同时substring对于特殊参数有特别的优化处理:

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); 
} 

由此看出,string对象背后并没有什么神奇之处,对字节码有了些了解可以更好的理解它。
其实常量池中还保存类及其方法的很多信息,如包名、类名、方法签名等等,有兴趣可以
深入研究。