字符串类String
String是一个特殊的包装类数据。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
String即可以用String str= new String("abc");的形式来创建,也可以用String str ="abc";的形式来创建。
字符串中的常用方法
方法名 | 简介 | 方法描述 |
---|---|---|
public String concat(String str) | 字符串的连接 | 该方法的参数为一个String类对象,作用是将参数中的字符串str连接到原来字符串的后面. |
public int length() | 求字符串的长度 | 返回字串的长度,这里的长度指的是字符串中Unicode字符的数目. |
public char charAt(int index) | 求字符串中某一位置的字符 | 该方法在一个特定的位置索引一个字符串,以得到字符串中指定位置的字符.值得注意的是, 在字符串中第一个字符的索引是0,第二个字符的索引是1,依次类推,最后一个字符的索引是length()-1. |
public boolean equals(Object anObject) | 字符串的比较 | 该方法比较两个字符串,和Character类提供的equals方法相似,因为它们都是重载Object类的方法. 该方法比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false. |
public String subString(int beginIndex) | 从字符串中提取子串 | 该方法从beginIndex位置起,从当前字符串中取出剩余的字符作为一个新的字符串返回. |
public int indexOf(int ch) | 字符串中单个字符的查找 | 该方法用于查找当前字符串中某一个特定字符ch出现的位置. 该方法从头向后查找,如果在字符串中找到字符ch,则返回字符ch在字符串中第一次出现的位置; 如果在整个字符串中没有找到字符ch,则返回-1. |
public String trim() | 字符串中多余空格的去除 | 该方法只是去掉开头和结尾的空格,并返回得到的新字符串.值得注意的是,在原来字符串中间的空格并不去掉. |
public native String intern(); | 指向字符串池中特定的常量池中的对象 | 如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象; 否则,将此String对象包含的字符添加到常量池中,并返回此String对象的引用。 |
String为什么设置成不可变
主要从以下三方面考虑:
1、保证 String 对象的安全性。假设 String 对象是可变的,那么 String 对象将可能被恶意修改。
2、保证 hash 属性值不会频繁变更,确保了唯一性,使得类似 HashMap 容器才能实现相应的 key-value 缓存功能。
3、可以实现字符串常量池
String在JVM的存储
代码示例
String str1 = "123";
String str2 = "123";
String str3 = "123";
String str4 = new String("123");
String str5 = new String("123");
String str6 = new String("123");
str1 == str2:true
str2 == str3:true
str3 == str4:false
str4 == str5:false
str5 == str6:false
JVM存储示例
创建String对象流程
对于JVM底层,String str = new String("123")
创建对象流程是什么?
- 在常量池中查找是否存在"123"这个字符串;若有,则返回对应的引用实例;若无,则创建对应的实例对象;
- 在堆中new一个String类型的"123"字符串对象;
- 将对象地址复制给str,然后创建一个应用。
注意:
若常量池里没有"123"字符串,则创建了2个对象;若有该字符串,则创建了一个对象及对应的引用。
创建String对象常见问题:
问题:
1.String str ="ab" + "cd";对象个数?
分析:若字符串常量池该字符串对象
- 字符串常量池:(1个对象)"abcd";
- 堆:无
- 栈:(1个引用)str
总共:1个对象+1个引用2.String str = new String("abc");对象个数?
分析:若字符串常量池该字符串对象
字符串常量池:(1个对象)"abc";
堆:(1个对象)new String("abc")
栈:(1个引用)str
总共:2个对象+1个引用
3.String str = new String("a" + "b");对象个数?
分析:若字符串常量池该字符串对象
- 字符串常量池:(3个对象)"a","b","ab";
- 堆:(1个对象)new String("ab")
- 栈:(1个引用)str
总共:4个对象+1个引用4.String str = new String("ab") + "ab";对象个数?
分析:若字符串常量池该字符串对象
- 字符串常量池:(1个对象)"ab";
- 堆:(1个对象)new String("ab")
- 栈:(1个引用)str
总共:2个对象+1个引用5.String str = new String("ab") + new String("ab");对象个数?
分析:若字符串常量池该字符串对象
- 字符串常量池:(1个对象)"ab";
- 堆:(2个对象)new String("ab"),new String("ab")
- 栈:(1个引用)str
总共:3个对象+1个引用6.String str = new String("ab") + new String("cd");对象个数?
分析:若字符串常量池该字符串对象
- 字符串常量池:(2个对象)"ab","cd";
- 堆:(2个对象)new String("ab"),new String("cd")
- 栈:(1个引用)str
总共:4个对象+1个引用7.String str3 = str1 + str2;对象个数?
String str1 = "ab"; String str2 = "cd"; String str3 = str1 + str2;
分析:若字符串常量池该字符串对象
- 字符串常量池:(2个对象)"ab","cd","abcd";
- 堆:无
- 栈:(3个引用)str1,str2,str3
总共:2个对象+3个引用
通过java.lang.String.intern()方法指定字符串对象
代码
String str1 = "123";
String str2 = new String("123");
String str3 = str2;
System.out.println("str1 == str2:" + (str1 == str2));
System.out.println("str1 == str3:" + (str1 == str3));
//通过java.lang.String.intern()方法指定字符串对象
String str4 = str2.intern();
System.out.println("str1 == str4:" + (str1 == str4));
结果:
str1 == str2:false
str1 == str3:false
str1 == str4:true
String的长度
java字符串String的最大长度,要分两个阶段,编译阶段及运行时阶段
编译阶段:
在我们使用字符串字面量直接定义String的时候,会把字符串在常量池中存储一份。常量池中的每一项常量都是一个表,都有自己对应的类型,对于索引定义了u2,就是无符号占2个字节。String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引用。
JVM的常量池最多可放65535个项。第0项不用。最后一项最多只能是65534(下标值)。而每一项中,若是放一个UTF-8的常量串,其长度最长是:65535个字节(不是字符)。
运行时阶段:
String内部是以char数组的形式存储,数组的长度是int类型,那么String允许的最大长度就是Integer.MAX_VALUE了,2147483647;又由于java中的字符是以16位存储的,因此大概需要4GB的内存才能存储最大长度的字符串。
String常见面试题
1. 如何比较两个字符串?用“=”还是equals
简单来说,“==”是用来检测俩引用是不是指向内存中的同一个对象,而equals()方法则检测的是两个对象的值是否相等。只要你想检测俩字符串是不是相等的,你就必须得用equals()方法。
2. 为什么安全敏感的字符串信息用char[]会比String对象更好?
String对象是不可变的就意味着直到垃圾回收器过来清扫之前它们都不会发生变化的。用数组的话,就可以很明确的修改它任何位置的字符元素。这样的话,如密码等安全敏感的信息就不会出现在系统的任何地方。
3. 字符串对象能否用在switch表达式中?
从JDK7开始的话,我们就可以在switch条件表达式中使用字符串了,也就是说7之前的版本是不可以的。
// java 7 only!
switch (str.toLowerCase()) {
case "a":
value = 1;
break;
case "b":
value = 2;
break;
}
4. 如何将字符串转换为整型数值?
int n = Integer.parseInt("10");
如此简单,经常使用有偶尔也会被遗忘。
5. 如何用空格去分隔字符串?
我们可以很便捷的使用正则表达式来进行分隔。“\s”就表示空格,还有如”",”\t”,”\r”,”\n”.
String[] strArray = aString.split("\s+");
6. subString()方法具体是都干了些啥?
在JDK6中,这个方法只会在标识现有字符串的字符数组上 给一个窗口来表示结果字符串,但是不会创建一个新的字符串对象。如果需要创建个新字符串对象,可以这样在结果后面+一个空的字符串:
str.subString(m, n) + ""
这么写的话就会创建一个新的字符数组来表示结果字符串。同时,这么写也有一定的几率让你的代码跑的更快,因为垃圾回收器会吧没有在使用的大字符串回收而留下子字符串。
Oracle JDK7中的subString()方法会创建一个新的字符数组,而不用之前存在的。看看这张图就会明白subString()方法在JDK6和JDK7中的区别。
7.String&StringBuilder&StringBuffer
String vs StringBuilder:StringBuilder是可变的,这就意味你在创建对象之后还可以去修改它的值。StringBuilder vs StringBuffer:StringBuffer是同步的,意味着它是线程安全的,但是就会比StringBuilder慢些。
8. 如何快速重复构造一段字符串?
在Python编程中,只需要用字符串去乘以一个数字就可以 搞定了,那在Java编程中,我们可以使用来自Apache Commons Lang包中的StringUtils类的repeat()方法。
String str = "abcd";
String repeated = StringUtils.repeat(str,3);
//abcdabcdabcd
9. 如何将时间格式的字符串转换成date对象?
String str = "Sep 17, 2013";
Date date = new SimpleDateFormat("MMMM d, yy", Locale.ENGLISH).parse(str);
System.out.println(date);
//Tue Sep 17 00:00:00 EDT 2013
10. 如何计数一个字符在某个字符串中出现的次数?
使用Apache Commons Lang包中的 StringUtils类就可以完成这个工作。
int n = StringUtils.countMatches("11112222", "1");
System.out.println(n);
网友评论