-----------android培训、java培训、java学习型技术博客、期待与您交流!------------
Java中只读类String和StringBuffer、StringBuilder类
一、String类
1、String类被final修饰符修饰,所以不能被继承;
2、字符串一旦被初始化就不可以被改变;
3、利用public String(char[] value)初始化String对象
这种半初始化也可以建立String对象
char[] ch = new char[5];
ch[3] = 'a';
ch[4] = 'b';
String s = new String(ch);
System.out.println(s);
4、在Java中,初始化String分为两种:
String s1 = "abc";
String s2 = new String("abc")
区别:方法1中,先在栈内存中查找有没有"abc"这个字符串对象存在,如果存在就把s1指向这个字符串对象;
如果不存在,编译时就在方法区中的静态常量池中建立一个"abc"对象,然后把就把s1指向这个字符串对象;
方法2中,执行方法1的过程,然后不论栈内存中是否已经存在"abc"这个字符串对象,
都会在堆中新建一个new String()对象,把"abc"这个对象的成员属性char[] value的栈内存地址赋给
new String()对象的成员属性char[] value。
5、equals()方法
public boolean equals(Object anObject)
将此字符串与指定的对象比较。当且仅当该参数不为 null ,并且是与此对象表示相同字符序列的
String 对象时,结果才为 true。
System.out.println(s1.equals(s2)); //true str5的值str6的值比对
6、本地intern()方法返回栈中值的内存地址
public native String intern();
String s3 = s2.intern();
当调用 intern 方法时,就是返回s1中栈的地址值。
class StringDemo{
public static void main(String[] args)
{
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
String s3 = s2.intern();
System.out.println(s1==s3);
}
}
结果:false
true
true
7、操作字符串的方法
(1)获取
a、字符串中包含的字符数,也就是字符串的长度;
int length();
b、根据位置获取位置上的某个字符;
char charAt(int index);
c、根据字符获取该字符在字符串中的位置;
int indexOf(int ch);返回ch在字符串中第一次出现的位置
int indexOf(int ch,int fromindex);//从fromindex指定的位置开始,获取ch在字符串中的出现的位置
int indexOf(String str);//从fromindex指定的位置开始,获取字符串str在字符串中的出现的位置
int indexOf(String str,int fromindex);//从fromindex指定的位置开始,获取str在字符串中的出现的位置
int lastIndexOf(int ch); //反向索引
(2)判断
a、字符串中是否包含某一个子串;
public boolean contains(CharSequence s);
注意:indexOf(String str)可以索引str第一次出现的位置,如果返回-1,表示str不在字符串中村子;
所以也可以用于对存储判读是否包含,例如 if(str.indexOf("aa")!=-1). 该方法既可以判断,也可以
获取出现的位置。
b、字符串是否不为空
public boolean isEmpty();
c、字符串是否以指定内容开头
public boolean startsWith(String prefix);
d、字符串是否以指定内容结束
public boolean endsWith(String suffix);
e、判断字符串内容是否相同,覆盖了Object类中的equals方法
public boolean equals(Object anObject);
f、判断字符串内容是否相同,但忽略大小写
public boolean equalsIgnoreCase(String anotherString);
(3)转换
a、将字符数组转成字符串。
构造函数:String(char[]);
String(char[],offset,count);//将字符数组中的一部分转成字符串
静态方法:
public static String copyValueOf(char[] data);
public static String copyValueOf(char[] data,int offset,int count);
public static String valueOf(char[] data);
b、将字符串转成字符数组。**
public char[] toCharArray();
c、将字节数组转成字符串。
String(byte[]);
String(byte[],offset,count);//将字节数组中的一部分转成字符串
d、将字符串转成字节数组。
public byte[] getBytes();
e、将基本数据类型转成字符串。
public static String valueOf(int i);
public static String valueOf(double d);
例如:3+"";转换为字符串也可以 String.valueOf(3);
特殊:字符串和字节数组在转换过程中,是可以指定编码表的。
(4)替换
public String replace(char oldChar,char newChar);
(5)切割
public String[] split(String regex);
(6)子串:获取字符串中的一部分。
public String substring(int beginIndex);
public String substring(int beginIndex,int endIndex);
(7)转换/去除空格/比较
a、将字符串转成大写或则小写。
public String toUpperCase();
public String toLowerCase();
b、将字符串两端的多个空格去除。
public String trim();
c、对两个字符串进行自然顺序的比较。
public int compareTo(String anotherString);
class StringMethodDemo
{
public static void method_case(){
String s = " Hello Java ";
sop(s.toLowerCase());
sop(s.toUpperCase());
sop(s.trim());
String s1 = "a1c";
String s2 = "aaa";
sop(s1.compareTo(s2));
}
public static void method_sub(){
String s = "abcdef";
sop(s.substring(2));//从指定位置开始到结尾。如果角标不存在,会出现字符串角标越界异常。
sop(s.substring(2,4));//包含头,不包含尾。s.substring(0,s.length());
}
public static void method_split(){
String s = "zhagnsa,lisi,wangwu";
String[] arr = s.split(",");
for(int x = 0; x<arr.length; x++)
{
sop(arr[x]);
}
}
public static void method_replace(){
String s = "hello java";
//String s1 = s.replace('q','n');//如果要替换的字符不存在,返回的还是原串。
String s1 = s.replace("java","world");
sop("s="+s);
sop("s1="+s1);
}
public static void method_trans(){
//字符数组转换为字符串
char[] arr = {'a','b','c','d','e','f'};
String s= new String(arr,1,3);
sop("s="+s);
//字符串转换为字符数组
String s1 = "zxcvbnm";
char[] chs = s1.toCharArray();
for(int x=0; x<chs.length; x++)
{
sop("ch="+chs[x]);
}
}
public static void method_is(){
String str = "ArrayDemo.java";
//判断文件名称是否是Array单词开头。
sop(str.startsWith("Array"));
//判断文件名称是否是.java的文件。
sop(str.endsWith(".java"));
//判断文件中是否包含Demo
sop(str.contains("Demo"));
//判断文件中是否包含.java,会有问题,如array.java.txt
sop(str.contains(".java"));
}
public static void method_get(){
String str = "abcdeakpf";
//长度
sop(str.length());
//根据索引获取字符。
sop(str.charAt(4));//当访问到字符串中不存在的角标时会发生StringIndexOutOfBoundsException。
//根据字符获取索引
sop(str.indexOf('m',3));//如果没有找到,返回-1.
//反向索引一个字符出现位置。
sop(str.lastIndexOf("a"));
}
public static void main(String[] args)
{
//method_case();
//method_trans();
method_is();
//method_get();
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
二、关于String的不可变设计:
String是不可改变类(记:基本类型的包装类都是不可改变的)的典型代表,也是Immutable设计模式的典型应用,
String变量一旦初始化后就不能更改,禁止改变对象的状态,从而增加共享对象的坚固性、减少对象访问的错误,
同时还避免了在多线程共享时进行同步的需要。
Immutable模式的实现主要有以下两个要点:
1.除了构造函数之外,不应该有其它任何函数(至少是任何public函数)修改任何成员变量。
2.任何使成员变量获得新值的函数都应该将新的值保存在新的对象中,而保持原来的对象不被修改。
String的不可变性导致字符串变量使用+号的代价:
例9:
String s = “a” + "b” + "c”;
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = s1 + s2 + s3;
分析:变量s的创建等价于 String s = “abc”; 由上面例子可知编译器进行了优化,这里只创建了一个对象。
由上面的例子也可以知道s4不能在编译期进行优化,其对象创建相当于:
StringBuffer temp = new StringBuffer();
temp.append(s1).append(s2).append(s3);
String s = temp.toString();
由上面的分析结果,可就不难推断出String 采用连接运算符(+)效率低下原因分析,形如这样的代码:
public class Test {
public static void main(String args[]) {
String s = null;
for(int i = 0; i < 100; i++) {
s += "a";
}
}
}
每做一次 + 就产生个StringBuffer对象,然后append后就扔掉。下次循环再到达时重新产生个StringBuffer对象,
然后append 字符串,如此循环直至结束。如果我们直接采用StringBuffer对象进行append的话,我们可以节省N - 1次
创建和销毁对象的时间。所以对于在循环中要进行字符串连接的应用,一般都是用StringBuffer或StringBulider对象来
进行append操作。
三、StringBuffer类
String不可变类的同志类,或者叫字符的容器类,是字符串缓冲区。
1、特点:
(1)长度是可变化的。
(2)可以字节操作多个数据类型。
(3)最终会通过toString方法变成字符串。
2、操作字符串的方法( C create U update R read D delete)
(1)存储
public StringBuffer append():将指定数据作为参数添加到已有数据结尾处。
public StringBuffer insert(index,数据):可以将数据插入到指定index位置。
(2)删除
public StringBuffer delete(start,end):删除缓冲区中的数据,包含start,不包含end。
public StringBuffer deleteCharAt(index):删除指定位置的字符。
(3)获取
public char charAt(int index); //获取指定位置的字符
public int indexOf(String str); //获取str的位置
public int lastIndexOf(String str);//获取str的最后的位置
public int length();//获取长度
public String substring(int start, int end); //获取从strat到end-1位置的字符串
(4)修改
public StringBuffer replace(start,end,str); //用字符串str替代从start到end-1的字符串
public void setCharAt(int index, char ch) ;//用ch字符替代index位置上的字符
(5)反转
public StringBuffer reverse();
(6)将缓冲区中指定数据存储到指定字符数组中。
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
四、StringBuilder类
1、特点
JDK1.5 版本之后出现了StringBuilder.一个可变的字符序列。
2、比较
StringBuffer是线程同步: 此类提供一个与 StringBuffer 兼容的 API,但不保证同步。
该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。
StringBuilder是线程不同步。
3、如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
4、它的方法是和StringBuffer类一样的,不过要注意
(1)因为没有线程锁,所以StringBuilder类的对象可以被多个线程同时操作;
(2)如果要在多线程中使用StringBuffer类对象,只要手动加锁就可以了。
class StringBufferDemo {
public static void sop(String str){
System.out.println(str);
}
public static void method_saveCharBuffer(){
StringBuffer sb = new StringBuffer("abcdef");
char[] chs = new char[6];
sb.getChars(1,4,chs,1);
for(int x=0; x<chs.length; x++)
{
sop("chs["+x+"]="+chs[x]+";");
}
}
public static void method_update(){
StringBuffer sb = new StringBuffer("abcde");
//sb.replace(1,4,"java");
sb.setCharAt(2,'k');
sop(sb.toString());
}
public static void method_del(){
StringBuffer sb = new StringBuffer("abcde");
sb.delete(1,3);
//清空缓冲区。
//sb.delete(0,sb.length());
//sb.delete(2,3);
//sb.deleteCharAt(2);
sop(sb.toString());
}
public static void method_add(){
StringBuffer sb = new StringBuffer();
sb.append("abc").append(true).append(34);
//StringBuffer sb1 = sb.append(34);
//sop("sb==sb1:"+(sb==sb1));
sb.insert(1,"qq");
sop(sb.toString());//abctrue34
//sop(sb1.toString());
}
public static void main(String[] args) {
//method_add();
//method_del();
//method_update();
//method_saveCharBuffer();
//StringBuilder类测试
StringBuilder sb = new StringBuilder("abcdef");
char[] chs = new char[6];
sb.getChars(1,4,chs,1);
for(int x=0; x<chs.length; x++)
{
sop("chs["+x+"]="+chs[x]+";");
}
}
}