java.lang.String
- String类型的特点:
1)String类型是不能被继承的;
2)String类型的对象是不可变的,也就是说我们每次修改字符串都是产生了新的对象;
3)由于String类型的对象是不可变的,使得我们把一些字符串存到常量池里,常量池中的对象是可以共享的; - HotSpot虚拟机的常量池在哪里呢?
JDK 1.6及之前 常量池是在方法区里的;
JDK 1.7在堆中单独划分了一块用来存储常量;
JDK 1.8从堆中拿出来放到了元空间Metaspace里,元空间在本地内存里; - String对象的底层存储:
JDK1.9之前是通过char[]来存储的;
JDK1.9之后是通过byte[]存储的; - String对象是怎么实现不可变的?
1)底层char[]是final修饰的,也就控制了该字符串对象长度的不可变;
2)底层的char[]是私有的,程序员是无法直接操作的,并且String类也没有提供修改方法,String类提供的所有方法都是返回新的对象; -
字符串的比较问题:
1)== 比较对象的地址://在常量池中相同的字符串常量比较才会返回true: public void cmp01(){ String s1 = "zzn"; String s2 = "zzn"; System.out.println(s1==s2);//true }
//在堆中的字符串和在常量池中的字符串==比较是不会相等的: public void cmp02(){ String s1 = new String("zzn"); String s2 = "zzn"; System.out.println(s1==s2);//false }
//在堆中的两个字符串==比较也是不会相等的: public void cmp03(){ String s1 = new String("zzn"); String s2 = new String("zzn"); System.out.println(s1==s2);//false }
2)equals()方法比较两个对象的内容:只要是内容相同不论是在常量池还是堆都是true;
public void cmp01(){ String s1 = "zzn"; String s2 = "zzn"; System.out.println(s1.equals(s2));//true }
public void cmp02(){ String s1 = new String("zzn"); String s2 = "zzn"; System.out.println(s1.equals(s2));//true }
public void cmp03(){ String s1 = new String("zzn"); String s2 = new String("zzn"); System.out.println(s1.equals(s2));//true }
3)equalsIgnoreCase()方法,忽略大小写比较内容,不论是在堆还是常量池只要内容上只有大小写差别就会返回true;
public void cmp01(){ String s1 = "zzn"; String s2 = "ZZN"; System.out.println(s1.equalsIgnoreCase(s2));//true }
public void cmp02(){ String s1 = new String("zzn"); String s2 = "ZZN"; System.out.println(s1.equalsIgnoreCase(s2));//true }
public void cmp03(){ String s1 = new String("ZZN"); String s2 = new String("zzn"); System.out.println(s1.equalsIgnoreCase(s2));//true }
4)字符串比较大小:
·自然排序:实现了java.lang.comparable接口://区分大小写,String类实现了java.lang.comparable接口中的public int compareTo(T o);方法; public void cmp01(){ String s1 = "zzna"; String s2 = "ZZN"; if (s1.compareTo(s2) > 0){ System.out.println(s1 + " > " + s2); }else if (s1.compareTo(s2) == 0){ System.out.println(s1 + " = " + s2); }else if (s1.compareTo(s2) < 0){ System.out.println(s1 + " < " + s2); } //结果:zzna > ZZN }
//不区分大小写,String类自己提供了public int compareToIgnoreCase(String str)方法; public void cmp01(){ String s1 = "zzn"; String s2 = "ZZN"; if (s1.compareToIgnoreCase(s2) > 0){ System.out.println(s1 + " > " + s2); }else if (s1.compareToIgnoreCase(s2) == 0){ System.out.println(s1 + " = " + s2); }else if (s1.compareToIgnoreCase(s2) < 0){ System.out.println(s1 + " < " + s2); } // 结果:zzn = ZZN }
·定制排序:Collator做比较器;
public static void main(String[] args) { String[] array = {"周震南","薛之谦","白敬亭"}; // getInstance();获取当前默认语言环境的Collator。 // getInstance(Locale.CHINA);指定语言环境为中文获得Collator比较器 Arrays.sort(array, Collator.getInstance(Locale.CHINA)); System.out.println(Arrays.toString(array)); }
- 字符串有几个对象问题;
1)String str = "zzn";只有常量池中的一个字符串对象;
2)string str = new String("zzn");在堆中有一个new出来的对象,在String pool中有一个字符串常量对象;
3)String str1 = new String("zzn");
String str2 = new String("zzn");在堆中有2个new出来的String对象,在String pool中有一个字符串常量对象(共享的); -
关于拼接结果在堆还是在 String pool的问题:
1)常量 + 常量 在Spring pool中;
2)常量 + 变量 在堆中;
3)变量 + 变量 在堆中;
4)**.intern() 在String pool中;public static void main(String[] args) { String s1 = "hello"; String s2 = "world!"; String s3 = "helloworld!"; // 常量变量拼接结果在堆中; String str1 = s1 + "world!"; // 变量变量拼接结果在堆中; String str2 = s1 + s2; // 常量常量拼接结果在String pool中; String str3 = "hello" + "world!"; System.out.println(s3==str1);//false System.out.println(s3==str2);//false System.out.println(s3==str3);//true } --------------------------------------------------------------------------------- public void test02() { final String s1 = "hello"; String s2 = "world!"; String s3 = "helloworld!"; // 被final修饰的s1也是字符串常量,常量常量拼接结果在String pool中; String str1 = s1 + "world!"; // 变量常量拼接结果在堆中; String str2 = s1 + s2; // 常量常量拼接结果在String pool中; String str3 = "hello" + "world!"; System.out.println(s3==str1);//true System.out.println(s3==str2);//false System.out.println(s3==str3);//true } --------------------------------------------------------------------------------- public void test03() { final String s1 = "hello"; String s2 = "world!"; String s3 = "helloworld!"; // 被final修饰的s1也是字符串常量,常量常量拼接结果在String pool中; String str1 = s1 + "world!"; // 用intern()方法把拼接的结果放到Spring pool中; String str2 = (s1 + s2).intern(); // 常量常量拼接结果在String pool中; String str3 = "hello" + "world!"; System.out.println(s3==str1);//true System.out.println(s3==str2);//true System.out.println(s3==str3);//true }
-
关于空字符串的问题:
1)哪些才是空字符串对象?public void nullString01(){ String s1;//局部变量未初始化 String s2 = null;//初始化为null,java.lang.NullPointerException String s3 = "";// String pool中的空字符串常量对象; String s4 = new String();//堆中的空字符串对象 String s5 = new String("");//一共两个对象 堆中的String对象,String pool中的空字符串常量对象; }
-
String类的常用方法(具体可查阅API):
1)普通方法:
① int length();返回字符串长度,返回的是字符的个数;
② Boolean isEmpty();判断字符串是否为空;
③ String toLowerCase();将字符串中所有字符都转换成对应的小写;
④ String toUpperCase();将字符串中所有字符都转换成对应的大写;
⑤ String trim();去掉字符串首尾的空格,中间的去不掉;
⑥ String concat();拼接字符串,等价于 + ;
2)char[]相关的方法:
① char[] toCharArray():将字符串转成字符数组;
② char charAt(int index):按索引取字符串中对应的字符;
③ String(char[] arr):构造器,用字符数组构成字符串;
④ String(char[] arr,int offset,int count):构造器,用字符数组的一部分构成字符串;
3)判断开头结尾的方法:
① Boolean startWith(xx):判断某字符串是否是以某字符或字符串开头;
② Boolean endWith(xx):判断某字符串是否以某字符或字符串结尾;
4)和查找有关的方法:
① Boolean contains(xx):判断是否包含某字符或字符串;
② int indexOf(xx):返回某字符第一次出现的下标或字符串第一次出现的开始下标,若不存在返回-1;
③ int lastIndexOf():返回某字符最后一次出现的下标或字符串最后一次出现的开始下标,若不存在返回 -1;
5)和截取有关的方法:
① String substring(int beginIndex):截取字符串从[beginIndex]到最后;
② String substring(int beginIndex,int endIndex):截取字符串[beginIndex,endIndex);
6)匹配规则相关的方法:
① Boolean matches(正则表达式):检测字符串是否满足给定正则的要求;
7)替换相关方法:
① String replace(target,value):替换字符串中所有出现的目标字符或字符串,支持正则匹配;
② String replaceAll():替换字符串中所有出现的目标字符或字符串,支持正则匹配;
③ String replaceFirst():替换字符串中第一次出现的目标字符,支持正则匹配;
8)拆分方法:
① String[ ] split(xx):以某字符或字符串拆分; - 因为String具有不可变性,一旦进行修改就会产生新的对象,所以引入了可变字符序列StringBuffer和StringBuilder;
1)StringBuffer和StringBuilder有什么区别呢?
StringBuilder | StringBuffer | |
---|---|---|
线程安全性 | 线程不安全 | 线程安全 |
一般实现中 | 快 | 慢 |
适用情况 | 单线程访问的字符串缓冲区 | 多线程共享的字符串缓冲区 |
2) StringBuffer和StringBuilder除了和String相似的方法 还有哪些常用方法?
① append("xxx"): 拼接方法;
② insert(int index, xx ): 插入方法;
③ delete(int start, int end): 按索引删除;
④ deleteCharAt(int index): 删除某个字符;
⑤ reverse(): 翻转字符串;
...(更多可查阅API)
- 当所做的字符串拼接操作较多时,可以根据线程情况选用StringBuffer或StringBuilder来代替String,因为StringBuffer和StringBuilder的拼接效率比String高一些;
声明:本文章是自学后编写,仅供参考,如有疏漏之处感谢指正;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。