java基础(三)java中String类的作用及常用方法,StringBuffer与StringBuilder的使用理解与String类的区别
先看String类的源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
从上面可以看出几点:
1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。
2)上面列举出了String类中所有的成员属性,从上面可以看出String类其实是通过char数组来保存字符串的。
字符串(String)的一些方法
字符串(String)的一些方法
翻看Java文档,可以看出String类为我们封装了很多的对字符串操作的方法:
int length()
返回此字符串的长度
char charAt(int index)
根据下标获取字符串的某个字符(可以获取某个特定位置的字符)
String concat(String str)
将指定字符串连接到此字符串的结尾(相当于“+”运算符)
boolean contains(CharSequence s)
判断此char值序列s是否在字符串中,存在返回true(可以判断此字符串是否存在某个子串)
boolean endWith(String suffix)
判断此字符串是否以指定的后缀结束(比如在上传图片时,判断上传文件的文件扩展名是否为.jpg)
boolean startWith(String perfix)
判断此字符串是否以指定的前缀开始
booean equals(Object anObject)
将此字符串与指定的字符串进行比较(这个方法是重写了String的父类Object的方法,用来判断两个字符串的值是否相同)
boolean equalsIgnoreCase(String anotherString)
将此字符串和另一个字符串进行比较,不考虑大小写
String format(String format,Object… args)
对字符串进行格式化吃书输出
int indexOf(int ch)
返回指定字符在此字符串中的第一次出现处的索引,不存在指定字符,返回-1
String intern()
返回字符串对象的规范化表示形式
boolean isEmpty()
当且仅当length()为0时返回true
int lastIndexOf(String str)
返回指定字符串在此字符串中最后一次出现的索引
boolean matches(String regex)
判断此字符串是否匹配给定的正则表达式
String replace(CharSequence target,CharSequence replacement)
替换字符串
String[] split(String regex)
根据给定的正则表达式来拆分此字符串
String substring(int beginIndex,int endIndex)
字符串截取,从beginIndex索引截取到endIndex处
char[] toCharArray()
把此字符串转换成一个新的char数组
String toLowerCase()
把此字符串中的所有字符都转换为小写
String toUpperCase()
把此字符串中的所有字符都转换为大写
String toString()
用字符串的形式来返回此对象本身(它已经是一个字符串)
String valueOf(int i)
返回int参数的字符串形式(也就是所谓的类型转换,相应的还有其他基础数据类型的,比如boolean,double,long,char)
String、StringBuffer和StringBuilder的区别
1.对象的可变与不可变
String类中使用字符数组来保存数据,因为有“final”修饰符,所以string对象是不可变的。如下:
private final char value[];
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存数据,这两种对象都是可变的。如下:
char[] value;
2.是否是线程安全
String中的对象是不可变的,也就可以理解为常量,所以是线程安全。
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。看如下源码:
public synchronized StringBuffer reverse() {
2 super.reverse();
3 return this;
4 }
5
6 public int indexOf(String str) {
7 return indexOf(str, 0); //存在 public synchronized int indexOf(String str, int fromIndex) 方法
8 }
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
3.StringBuilder与StringBuffer共同点
StringBuilder与StringBuffer有公共的抽象父类AbstractStringBuilder。
抽象类与接口的一个区别是:抽象类中可以定义一些子类的公共方法,子类只需要增加新的功能,不需要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。
StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(…)。只是StringBuffer会在方法上加synchronized关键字,进行同步。
如果程序不是多线程的,那么使用StringBuilder效率高于StringBuffer。
创建了几个对象的问题
String str1 = "abc";
String str2 = new String("abc");
对于1中的 String str1 = “abc”,首先会检查字符串常量池中是否含有字符串abc,如果有则直接指向,如果没有则在字符串常量池中添加abc字符串并指向它.所以这种方法最多创建一个对象,有可能不创建对象。
对于2中的String str2 = new String(“abc”),首先会在堆内存中申请一块内存存储字符串abc,str2指向其内存块对象。同时还会检查字符串常量池中是否含有abc字符串,若没有则添加abc到字符串常量池中。所以 new String()可能会创建两个对象。
所以如果以上两行代码在同一个程序中,则1中创建了1个对象,2中创建了1个对象。如果将这两行代码的顺序调换一下,则1 String str2 = new String(“abc”)创建了两个对象,而2 String str1 = "abc"没有创建对象。
String的匹配相等问题
使用String类经常需要对两个字符串进行对比,看是否相等。有==和equals两种选择(String重写了equals方法),这两者方法区别大:
比对象的内容是否相等使用equals(),比较两个引用是否指向同一个对象时用==;equals()是看内容是否相等,比较好理解。而==是看是否属于同一个对象。
首先还要明白这个概念:常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。主要看编译期字符串能否确定。
String ok="ok";
String ok1=new String("ok");
System.out.println(ok==ok1);//fasle
ok指向字符串常量池,ok1指向new出来的堆内存块,new的字符串在编译期是无法确定的。所以输出false。
String ok="apple1";
String ok1="apple"+1;
System.out.println(ok==ok1);//true
编译期ok和ok1都是确定的,字符串都为apple1,所以ok和ok1都指向字符串常量池里的字符串apple1。指向同一个对象,所以为true