Java中String类的整理

(学习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:

  1. String str1 = "123" : 只在String池中创建了对象,如果池中已经有“123”的String对象,则str1直接指向该对象
  2. 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");

五,字符串的拼接

  1. 加号 “+”

  2. String contact() 方法

  3. StringUtils.join() 方法

  4. StringBuffer append() 方法

  5. 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

十一.Intern

https://www.cnblogs.com/aloenfs/p/9127353.html

原文地址:https://www.cnblogs.com/cdbb/p/12435516.html