String是一个对象
String不属于8种基本数据类型(byte, char, short, int, float, long, double, boolean),String是对象,所以其默认值是null。
String是一种特殊的对象,有其它对象没有的一些特性,通过JDK发现:
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 public String() { this.value = new char[0]; } public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } |
- String类是final的,不可被继承
- String类是的本质是字符数组char[], 并且其值不可改变,每一个构造的String对象,都是作为常量存储在内存中
- String类对象有个特殊的创建的方式,就是直接指定比如String x = "abc","abc"就表示一个字符串对象;而x是"abc"对象的地址,也叫做"abc"对象的引用。
- String对象可以通过 “+” 串联,串联后会生成新的字符串。
String对象的创建
归纳起来有三类:
- 使用new关键字创建字符串,比如String s1 = new String("abc");
- 直接指定。比如String s2 = "abc";
- 使用串联生成新的字符串。比如String s3 = "ab" + "c";
创建原理
public static void main(String[] args){ String s0 = "adanac"; String s1 = "adanac"; String s2 = "ada" + "nac"; System.out.println(s0 == s1); // true System.out.println(s0 == s2); // true }
例子中的s0和s1中的”adanac”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;
当使用String s1 = "adanac"; 方式时,JVM会拿着"adanac"在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
而”ada”和”nac”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中”adanac”的一个引用。
所以我们得出s0==s1==s2!
public static void main(String[] args){ String s0 = "adanac"; String s1 = new String("adanac"); String s2 = "ada" + new String("nac"); System.out.println(s0 == s1); // false System.out.println(s0 == s2); // false System.out.println(s1 == s2); // false }
用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。
此例中s0还是常量池中"adanac"的应用,s1因为无法在编译期确定,所以是运行时创建新对象”adanac”的引用,s2因为有后半部分new String("nac")所以也无法在编译期确定.
常量池(constant pool)
指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。
关于 equals() 和 ==
equals对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。
常见的操作方法
获取
public class Test { public static void main(String srgs[]) { String str = "hello java!" ; String str1 = new String("hello java!") ; //str 和 str1 的区别在于:str 内存中有一个对象,而str1 内存中有两个对象。 sop(str.length()) ; sop(str.charAt(i)) ; sop(str.indexOf('a')) ; sop(str.indexOf('a',7)) ; sop(str.indexOf("java")) ; sop(str.lastIndexOf('a')) ; } //打印函数: public static void sop(Object obj) { System.out.println(obj); } }
- 字符串中包含的字符数,即字符串的长度; int length() ;注意:String 类的 length() 是一个方法; 而 char 类型数组调用的length , 是属性。
- 根据位置获取位置上某个字符。 char charAt(int index) ; index 是下标。
- 根据字符获取该字符在字符串中的位置:
-
- int indexOf(int ch) ; 返回的是 ch 在字符串中第一次出现的位置。其中 ch 是字符的ASCII 码。
- int indexOf(int ch , int fromIndex) ; 从fromIndex 指定位置开始,在字符串中第一次出现的位置.
- int indexOf(String st) ; 返回的是 st 在字符串中第一次出现的位置。
- int lastIndexOf(int ch) ; 返回指定字符在此字符串中最后一次出现处的索引。
判断
public class Test{ public static void main(String args[]) { String str1 = "hello java!" ; String str2 = new String("hello java!") ; System.out.println(str1.equals(str2)); //true [String类重写了Object类的equals 方法] System.out.println(str1 == str2); //false } }
判断常用的方法有:
1、判断字符串中是否包含某一个字串。
boolean contains(CharSequence cs) ;
2、字符串中是否为空:
boolean isEmpty() ; 其原理就是判断字符长度是否为0。
3、判断字符串是否以指定类容开头:
boolean startsWith(String str) ;
4、判断字符串是否以指定类容结尾:
boolean endsWith(String cs) ;
5、判断字符串内容是否相等:
boolean equals(Obeject obj) ;
6、 判断内容是否相同,并忽略大小写。
boolean equalsIgnoreCase(String str)
转换
public class Test { public static void main(String args[]) { char[] ch = {'h','e' ,'l' ,'l' ,'o' ,' ' , 'j' , 'a' , 'v' ,'a'} ; // 构造函数转换: // 将字符数组转换成字符串: String str1 = new String (ch) ; System.out.println(str1); // 从ch[] 下标 6开始,后的4个字符 ,转换成字符串。 String str2 = new String (ch,6,4) ; System.out.println(str2); // 静态方法: // 将字符数组转换成字符串: String str3 = String.copyValueOf(ch) ; System.out.println(str3); // 从ch[] 下标 6开始,后的4个字符 ,转换成字符串。 String str4 = String.copyValueOf(ch,0,5) ; System.out.println(str4); String str = "hello java" ; // 将字符串转换成字符数组; char[] ch1 = str.toCharArray() ; for(int i = 0 ; i < ch1.length ; i ++) System.out.print("'"+ch1[i] +"'"); System.out.println(); } }
1、将字符数组转换成字符串:
构造方法:String(char[] ch)
String(char[] ch , int offset , int count ) ; 将字符数组中的一部分转成字符串。
其中:offset 参数是子数组第一个字符的索引;count 参数指定子数组的长度。如果从offset 后面的字符数小于count 则会异常。
注意:该子数组的内容已被复制;后续对字符数组的修改不会影响新创建的字符串。
2、将字符串转换成字符数组。
char[] toCharArray() ;
3、将字节数转成字符串。
构造方法:String(byte[] by) ;
String(byte[] by , int offset , int count) ;
4、将字符串转成字节数组。
byte[] getByte() ;
5、将基本数据类型转换成字符串。
static String valueOf(基本数据类型)
替换、切割、去除空格和比较
- String replace(char oldChar , char newChar) : 返回一个新的字符串,它是通过用
newChar
替换此字符串中出现的所有oldChar
得到的。 - String[] split(String regex) : 根据给定正则表达式的匹配拆分此字符串。
- String trim():将字符串两端的多个空格去除
- int compareTo(String str):对两个字符串进行自然顺序的比较。 ; 当另一个字符串大于该字符串时,返回负数;相等,则返回0;否则返回正数。
String str = " hello,java,Adanac " ; //替换字符 String str1 = str.replace(',', ' ') ; //切割 String[] str2 = str.split(",") ; // 除去字符串两端的多个空格: System.out.println(str1.trim()); String str2 = "hello world " ; //对比两个字符串进行自然顺序的比较 System.out.println(str.compareTo(str2));
练习
1,模拟一个trim方法,去除字符串两端的空格。
2,将一个字符串进行反转。将字符串中指定部分进行反转,"abcdefg";abfedcg
class StringTest { public static void sop(String str) { System.out.println(str); } public static void main(String[] args) { String s = " ab cd "; sop("("+s+")"); s = myTrim(s); sop("("+s+")"); sop("("+reverseString(s)+")"); } //练习二:将字符串反转。 /* 思路: 1,将字符串变成数组。 2,对数组反转。 3,将数组变成字符串。 */ public static String reverseString(String s,int start,int end) { //字符串变数组。 char[] chs = s.toCharArray(); //反转数组。 reverse(chs,start,end); //将数组变成字符串。 return new String(chs); } public static String reverseString(String s) { return reverseString(s,0,s.length()); } private static void reverse(char[] arr,int x,int y) { for(int start=x,end=y-1; start<end ; start++,end--) { swap(arr,start,end); } } private static void swap(char[] arr,int x,int y) { char temp = arr[x]; arr[x] = arr[y]; arr[y] = temp; } //练习一,去除字符串两端空格。 /*思路: 1,判断字符串第一个位置是否是空格,如果是继续向下判断,直到不是空格为止。 结尾处判断空格也是如此。 2,当开始和结尾都判断到不是空格时,就是要获取的字符串。 */ public static String myTrim(String str) { int start = 0,end = str.length()-1; while(start<=end && str.charAt(start)==' ') start++; while(start<=end && str.charAt(end)==' ') end--; return str.substring(start,end+1); } }
3,获取一个字符串在另一个字符串中出现的次数。
4,获取两个字符串中最大相同子串。第一个动作:将短的那个串进行长度一次递减的子串打印。
class StringTest { /* 练习三。 获取一个字符串在另一个字符串中出现的次数。 "abkkcdkkefkkskk" 思路: 1,定义个计数器。 2,获取kk第一次出现的位置。 3,从第一次出现位置后剩余的字符串中继续获取kk出现的位置。 每获取一次就计数一次。 4,当获取不到时,计数完成。 */ public static int getSubCount(String str,String key) { int count = 0; int index = 0; while((index=str.indexOf(key))!=-1) { sop("str="+str); str = str.substring(index+key.length()); count++; } return count; } /* 练习三,方式二。 */ public static int getSubCount_2(String str,String key) { int count = 0; int index = 0; while((index= str.indexOf(key,index))!=-1) { sop("index="+index); index = index + key.length(); count++; } return count; } public static void main(String[] args) { String str = "kkabkkcdkkefkks"; ///sop("count====="+str.split("kk").length);不建议使用。 sop("count="+getSubCount_2(str,"kk")); } public static void sop(String str) { System.out.println(str); } } class StringTest { /* 练习四。 获取两个字符串中最大相同子串。第一个动作:将短的那个串进行长度一次递减的子串打印。 "abcwerthelloyuiodef" "cvhellobnm" 思路: 1,将短的那个子串按照长度递减的方式获取到。 2,将每获取到的子串去长串中判断是否包含, 如果包含,已经找到!。 */ public static String getMaxSubString(String s1,String s2) { String max = "",min = ""; max = (s1.length()>s2.length())?s1: s2; min = (max==s1)?s2: s1; sop("max="+max+"...min="+min); for(int x=0; x<min.length(); x++) { for(int y=0,z=min.length()-x; z!=min.length()+1; y++,z++) { String temp = min.substring(y,z); sop(temp); if(max.contains(temp))//if(s1.indexOf(temp)!=-1) return temp; } } return ""; } public static void main(String[] args) { String s1 = "ab"; String s2 = "cvhellobnm"; sop(getMaxSubString(s2,s1)); } public static void sop(String str) { System.out.println(str); } }
StringBuffer类
StringBuffer 对象则代表一个字符序列可变的字符串。当一个 StringBuffer 被创建以后,通过StringBuffer 提供的一系列方法可以改变这个字符串对象的字符序列,一旦通过StringBuffer 生成了最终想要的字符串,就可以调用它的toString 方法将其转换成一个String 对象。
StringBuffer类被final修饰,不能被继承。
StringBuffer和数组都是容器,StringBuffer作为容器类的特点:
- 长度是可变的
- 可以操作多个数据类型
- 使用toString()转换成字符串
StringBuffer类常用方法
添加:
- StringBuffer append(数据) : 将指定的数据作为参数添加到已有的数据结尾处。返回的还是原缓冲区对象。
- StringBuffer insert(int index , 数据) : 可以将数据插入到指定角标index 位置。注意:index不能越界。
删除:
- StringBuffer delete(int start , int end) ;删除缓冲区的数据,包含start,不包含end。
- StringBuffer deleteCharAt(int index) ; 删除指定位置的字符。
获取:
- char charAt(int index) ; 获取指定位置的字符。
- void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将字符从此序列复制到目标字符数组 dst。
- int indexOf(String str) ; 获取子串第一次出现的位置。
- int lastIndexOf(String str) 返回最右边出现的指定子字符串在此字符串中的索引。
- int lastIndexOf(String str, int fromIndex) 返回最后一次出现的指定子字符串在此字符串中的索引。
- int length() 返回长度(字符数)。
- String toString() 返回此序列中数据的字符串表示形式。
- String substring(int start) 返回一个新的 String,它包含此字符序列当前所包含的字符子序列。
- String substring(int start, int end) 返回一个新的 String,它包含此序列当前所包含的字符子序列。
注意:获取方法和String 类中的方法类似。
修改 :
- StringBuffer replace(int start , int end , String str):使用给定String 中字符代替此序列中的子串中的字符。
- void setChatAt(int index , char ch) :将给定索引出的字符设置成ch .
- StringBuffer reverse() :将此字符序列用其反转形式取代。
- void setCharAt(int index, char ch) : 将给定索引处的字符设置为 ch。
- void setLength(int newLength) : 设置字符序列的长度。
public class StringBufferDemo { public static void main(String[] args) { System.out.println(""); DeleteString(new StringBuffer("hello java")) ; System.out.println("-------------------------------"); ReplaceString(new StringBuffer("hello java")) ; } public static void CreateString(StringBuffer stringBuffer ) { // 添加数据到stringBuffer 结尾处, stringBuffer.append("hello").append("java").append(520).append(true) ; System.out.println(stringBuffer); //在指定位置添加数据。 stringBuffer.insert(0, "heima,"); System.out.println(stringBuffer); } public static void DeleteString(StringBuffer stringBuffer) { //删除start至end的字符序列。 stringBuffer.delete(0,6); System.out.println(stringBuffer); //删除指定位置的字符 stringBuffer.deleteCharAt(1) ; System.out.println(stringBuffer); } public static void ReplaceString(StringBuffer stringBuffer) { //替换指定字符序列。 stringBuffer.replace(6, stringBuffer.length(), "adanac") ; System.out.println(stringBuffer); stringBuffer.setCharAt(5, ',') ; System.out.println(stringBuffer); //反转 stringBuffer.reverse(); System.out.println(stringBuffer); } }
StringBuilder类
- 一个可变的字符序列
- 该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。
StringBuilder 类和 StringBuffer 类基本相似:都是可变的字符序列。
在不用考虑线程安全的情况下使用 StringBuilder 类。
StringBuider 类和 StringBuffer 类二者之间的区别
- StringBuilder类是线程不同步的,没有实现线程安全功能,所以性能略高,它比 StringBuffer 要快
- StringBuffer类是线程同步的,线程安全的。