(学习java中的String类型)
一,String的内存模型
(jdk7以后)
//java String类
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
}
String str1 = "123";
String str2 = "123";
//str1==str2,相同对象;
String str2 = "1234";
//str1 != str2,不同对象;且str2的地址变化了
str1 += str2;
//str1 != str2,str1的地址也变化了;
String str1 = “ABC”;
//可能创建一个或者不创建对象
String str2 = new String(“ABC”);
//至少创建一个对象,也可能两个
String池和heap:
- String str1 = "123" : 只在String池中创建了对象,如果池中已经有“123”的String对象,则str1直接指向该对象
- String str2 = new String("123") : 在heap中开辟一块空间存放str2对象(一定会执行),如果String池当中已经有“123”,直接指向“123”,否则在String 池中创建对象
二,jdk6和jdk7对String处理的不同
jdk6:
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public String substring(int beginIndex, int endIndex) {
//check boundary
return new String(offset + beginIndex, endIndex - beginIndex, value);
}
subString时新建一个String对象,和原对象共享同一个value数组,只改变begin和end数值
问题:如果字符串很长,我们只需要其中的一小段,却引用了整个value数组,可能导致内存泄漏
解决方法:x = x.substring(x, y) + "";
jdk7:
//JDK 7
public String(char value[], int offset, int count) {
//check boundary
this.value = Arrays.copyOfRange(value, offset, offset + count);
}
public String substring(int beginIndex, int endIndex) {
//check boundary
int subLen = endIndex - beginIndex;
return new String(value, beginIndex, subLen);
}
三,repalcefirst replatall 和repalce区别
String src = new String("ab43a2c43d");
System.out.println(src.replace("3","f"));=>ab4f2c4fd.
System.out.println(src.replace('3','f'));=>ab4f2c4fd.
System.out.println(src.replaceAll("\d","f"));=>abffafcffd.
System.out.println(src.replaceAll("a","f"));=>fb43fc23d.
System.out.println(src.replaceFirst("\d,"f"));=>abf32c43d
System.out.println(src.replaceFirst("4","h"));=>abh32c43d.
//String类中的函数:
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public String replaceFirst(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
public String replace(CharSequence target, CharSequence replacement) {
return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}
private String pattern;
private int flags;
private transient volatile boolean compiled = false;
private transient String normalizedPattern;
transient Node root;
transient Node matchRoot;
transient int[] buffer;
transient volatile Map<String, Integer> namedGroups;
transient GroupHead[] groupNodes;
private transient int[] temp;
transient int capturingGroupCount;
transient int localCount;
private transient int cursor;
private transient int patternLength;
private transient boolean hasSupplementary;
//Pattern类中的函数:
public static Pattern compile(String regex) {
return new Pattern(regex, 0);
}
public Matcher matcher(CharSequence input) {
if (!compiled) {
synchronized(this) {
if (!compiled)
compile();
}
}
Matcher m = new Matcher(this, input);
return m;
}
public final class Matcher implements MatchResult {
Pattern parentPattern;
int[] groups;
int from, to;
int lookbehindTo;
CharSequence text;
static final int ENDANCHOR = 1;
static final int NOANCHOR = 0;
int acceptMode = NOANCHOR;
int first = -1, last = 0;
int oldLast = -1;
int lastAppendPosition = 0;
int[] locals;
boolean hitEnd;
boolean requireEnd;
boolean transparentBounds = false;
boolean anchoringBounds = true;
}
四,String 对 ‘+’ 号的重载
//1.用stringbuilder完成重载
String s1 = "yves";
String s2 = s1 + "he";
String s1 = "yves";
String s2 = (new StringBuilder(String.valueOf(s1))).append("he").toString();
//2.编译器期间执行完字符串的连接
String s1 = "yves" + "he";
System.out.println(s1 == "yveshe");
String s1 = "yveshe";
System.out.println(s1 == "yveshe");
五,字符串的拼接
-
加号 “+”
-
String contact() 方法
-
StringUtils.join() 方法
-
StringBuffer append() 方法
-
StringBuilder append() 方法
- 方法1 加号 “+” 拼接 和 方法2 String contact() 方法 适用于小数据量的操作,代码简洁方便,加号“+” 更符合我们的编码和阅读习惯;
- 方法3 StringUtils.join() 方法 适用于将ArrayList转换成字符串,就算90万条数据也只需68ms,可以省掉循环读取ArrayList的代码;
- 方法4 StringBuffer append() 方法 和 方法5 StringBuilder append() 方法 其实他们的本质是一样的,都是继承自AbstractStringBuilder,效率最高,大批量的数据处理最好选择这两种方法。
- 方法1 加号 “+” 拼接 和 方法2 String contact() 方法 的时间和空间成本都很高(分析在本文末尾),不能用来做批量数据的处理。
六,String.valueof()和Integer.toString()的不同
相同:都可以将int转为字符串;
不同:String.valueof()有大量的重载方法(double ,数组,对象。。。。);Integer.toString()只能转Int
七,(String)、toString、String.valueOf(obj)的区别
String强转会报异常
obj.toString:如果obj为null报错
String.valueOf(obj):如果obj为null,返回 “null” 字符串(不会出现空指针异常),而不是null。
八,switch对字符串的支持(jdk1.7之后)
String转成hashcode处理,hash是一个int
两个switch,第一个switch决定执行哪一步,第二个switch真正执行。
如果有string的hash冲突,则在第一个case中调用str.equals()方法比较字符串的内容。
九,字符串池
https://www.cnblogs.com/tongkey/p/8587060.html)]https://www.cnblogs.com/tongkey/p/8587060.html
https://www.cnblogs.com/huajiezh/p/6565301.html
1," " 引号创建的字符串在字符串池中
2,new,new创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则,将使得堆中的字符串永远是池中的子集,导致浪费池的空间)!
另外,对字符串进行赋值时,如果右操作数含有一个或一个以上的字符串引用时,则在堆中再建立一个字符串对象,返回引用;如String s=str1+ "blog";
String s1 = "hello";
String s2 = "hello";
String s3 = "he" + "llo";
String s4 = "hel" + new String("lo");
String s5 = new String("hello");
String s6 = s5.intern();
String s7 = "h";
String s8 = "ello";
String s9 = s7 + s8;
//在jdk1.6,1.7,1.8下运行的结果为
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
System.out.println(s1==s4);//false
System.out.println(s1==s9);//false
System.out.println(s4==s5);//false
System.out.println(s1==s6);//true
String s1 = new String("hello");
String intern1 = s1.intern();
String s2 = "hello";
System.out.println(s1 == s2);//1.6:F , 1.7:F
String s3 = new String("hello") + new String("hello");
String intern3 = s3.intern();
String s4 = "hellohello";
System.out.println(s3 == s4);//1.6:F , 1.7:T
String s1 = new String("hello");
String s2 = "hello";
String intern1 = s1.intern();
System.out.println(s1 == s2);//1.6:F , 1.7:F
String s3 = new String("hello") + new String("hello");
String s4 = "hellohello";
String intern3 = s3.intern();
System.out.println(s3 == s4);//1.6:F , 1.7:F
十,Java Class文件中的常量池
https://blog.csdn.net/zhidawujian/article/details/79041943