zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    主席树学习记录
    P1072 Hanson 的趣味题 题解
    好文章收集
    计算几何专题
    小问题
    CSP-S2020题解
    上下界网络流
    想到的无法解决的点子
    省选联考2020组合数问题
    省选数学复习
  • 原文地址:https://www.cnblogs.com/cdbb/p/12435516.html
Copyright © 2011-2022 走看看