• 源码学习-String类


    最近在扫描CodeDex时报了一个不能使用String.intern()的字符串来做锁对象的告警,对这个问题有疑问查了些资料,顺便学习一下String类的源码。

    1.类定义 String 被final修饰,是叶子类,不能不继承。实现了Serializable,Comparable,CharSequence 接口

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {...}

    Serializable:实现此接口来支持序列化和反序列化,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的

    Comparable:实现此接口的对象列表(和数组)可以通过 Collections.sort (和 Arrays.sort )进行自动排序

    CharSequence:字符序列,String本质是通过字符数组实现的

    2.属性

    2.1 value final的数组,用来储存String对象的字符

    2.2 hash String对象的HashCode

    2.3 serialPersistentFields ?在序列化流协议中String类会被特别包装,String对象会被写入到一个ObjectOutputStream...

    3.构造方法

    3.1 无参数构造方法默认返回空的字符串,因为String是不可变的,所有没有必要使用此构造函数

    1 public String() {
    2         this.value = "".value;
    3     }

    3.2

    1 public String(String original) {
    2         this.value = original.value;
    3         this.hash = original.hash;
    4     }

    3.3

    1 public String(char value[]) {
    2         this.value = Arrays.copyOf(value, value.length);
    3     }

    3.4

    public String(byte bytes[]) {//用默认的charset进行decode
             this(bytes, 0, bytes.length);
         }
     
    public String(byte bytes[], int offset, int length) {
             checkBounds(bytes, offset, length);
             this.value = StringCoding.decode(bytes, offset, length);
        }
    public String(byte bytes[], int offset, int length, Charset charset) {
            if (charset == null)
                throw new NullPointerException("charset");
            checkBounds(bytes, offset, length);
            this.value =  StringCoding.decode(charset, bytes, offset, length);
        }

    3.5 把此String对象的字符copy到dst数组,dst数组中从dstBegin的位置开始放置,此方法不进行任何边界校验

    void getChars(char dst[], int dstBegin) {
            System.arraycopy(value, 0, dst, dstBegin, value.length);
        }

    3.6 比较此对象从toffset位置的len长度字符数组是否和other对象的ooffset位置的len长度字符数组是同一个数组

    /*
    *比较本对象从toffset位置开始的len长度的char数组是否和other对象的ooffset位置开始的len长度的char数组是同一个数组
    */
    public boolean regionMatches(int toffset, String other, int ooffset,
                int len) {...}
    /*
    *带boolean参数的表示是否忽略大小写
    */
    public boolean regionMatches(boolean ignoreCase, int toffset,
                String other, int ooffset, int len) {...}
    /*
    *在equalsIgnoreCase方法中调用了带boolean参数的regionMatches
    */
    public boolean equalsIgnoreCase(String anotherString) {
        ...
        }

    3.7 是否以特定的字符串开头和结尾

    public boolean startsWith(String prefix, int toffset) {...}
    public boolean endsWith(String suffix) {...}//endsWith调用的startsWith

    3.8 indexOf系列

    View Code

    3.9

    public String substring(int beginIndex) {...}

    3.10 concat() 本对象之后连接字符串,返回新生成新的字符串

    public String concat(String str) {
            int otherLen = str.length();
            if (otherLen == 0) {
                return this;
            }
            int len = value.length;
            char buf[] = Arrays.copyOf(value, len + otherLen);
            str.getChars(buf, len);
            return new String(buf, true);
        }

    3.11 校验字符串是否符合正则表达式

    public boolean matches(String regex) {...}

    3.12 delimiter做连接符连接字符串列表或数组

    public static String join(CharSequence delimiter, CharSequence... elements) {
            Objects.requireNonNull(delimiter);
            Objects.requireNonNull(elements);
            // Number of elements not likely worth Arrays.stream overhead.
            StringJoiner joiner = new StringJoiner(delimiter);
            for (CharSequence cs: elements) {
                joiner.add(cs);
            }
            return joiner.toString();
        }

    e.g.

    public static void main(String[] args)
        {
            List<String> names=new ArrayList<String>();
            names.add("1");
            names.add("2");
            names.add("3");
            System.out.println(String.join("-", names));
    
            String[] arrStr=new String[]{"a","b","c"};
    
            System.out.println(String.join("-", arrStr));
        }

    输出:

    3.13 去除字符串前后空格返回生成的新的子字符串

    public String trim() {...}

    3.14 格式化字符串

    3.14.1 方法签名

    public static String format(String format, Object... args) {...}

    3.14.2 转换符

     

    说    明 

    示    例

    %s

    字符串类型

    "mingrisoft"

    %c

    字符类型

    'm'

    %b

    布尔类型

    true

    %d

    整数类型(十进制)

    99

    %x

    整数类型(十六进制)

    FF

    %o

    整数类型(八进制)

    77

    %f

    浮点类型

    99.99

    %a

    十六进制浮点类型

    FF.35AE

    %e

    指数类型

    9.38e+5

    %g

    通用浮点类型(f和e类型中较短的)

     

    %h

    散列码

     

    %%

    百分比类型

    %n

    换行符

     

    %tx

    日期与时间类型(x代表不同的日期与时间转换符

    3.14.3 e.g.

    System.out.println(String.format("现在的时间是:%d-%d-%d %d:%d:%d",2011,1,2,15,29,30));

    输出结果:

    3.15 valueOf

    public static String valueOf(Object obj) {
            return (obj == null) ? "null" : obj.toString();
        }

    3.16 String类私有维护的String pool 初始化时是空的,当对象s调用intern方法时,如果pool中已存在与之equals为true的t对象,那么池中存在的t对象会被返回,否则新的String对象会被加入到pool中,然后返回这个String对象的引用。

    此得出结论:只要s.equals(t),s.intern() == t.intern() 为true

    public native String intern();

    当使用String s = "abc"方式创建字符串时,字符串会自动加入常量池,而当使用String s = new String("abc")方式创建时,只有调用了s.intern()方法才会把s加入常量池

    String pool default size:

    7u40之前:1009,

    7u40+ to 8:60013

    java6的时候存在PermGen区,容易造成oom,java7之后改为存在Heap区

    7u02之后可以用-XX:StringTableSize=100003 设置JVM参数

    (参考http://java-performance.info/string-intern-in-java-6-7-8/)

  • 相关阅读:
    python基础()
    《野草在歌唱》读后感 读书笔记
    《饥饿的盛世》读后感 读书笔记
    《T.S.艾略特传:不完美的一生》读后感
    《宋徽宗》读后感 读书笔记
    《孔子传》读后感 读书笔记
    《武曌》读后感 读书笔记
    《百岁人生》读后感 读书笔记
    《曾国藩的正面与侧面》读后感 读书笔记
    《洞见》读后感 读书笔记
  • 原文地址:https://www.cnblogs.com/cici20166/p/6298489.html
Copyright © 2020-2023  润新知