zoukankan      html  css  js  c++  java
  • JDK源码之StringBuffer与StringBuilder类分析

    一 概述

    • StringBuffer类被 final 所修饰,不能被继承,StringBuffer继承了AbstractStringBuilder类,
      是一个可变的字符序列,并且类中方法都有synchronized修饰,实现了线程安全
    • StringBuilder类也被final修饰,继承了AbstractStringBuilder类,与StringBuffer区别是没有实现线程安全,方法逻辑都是调用的父类方法逻辑

    二 StringBuffer源码解析

    大部分方法都调用super父类逻辑,所以这里只举个别例子, 父类解析地址: https://www.cnblogs.com/houzheng/p/12153734.html

        /**
         * 返回最后一次toString的缓存值,一旦StringBuffer被修改就清除这个缓存值,
         * 用于toString方法的时候如果此值不为空,则直接使用返回,不必进行数组copy,以提高性能
         */
        private transient String toStringCache;
    
        /**
         * 调用父类构造器进行byte数组初始化,默认长度初始化为16或者(32,jvm参数关闭压缩时)
         */
        @HotSpotIntrinsicCandidate
        public StringBuffer() {
            super(16);
        }
    
        /**
         * 指定byte数组长度初始化
         */
        @HotSpotIntrinsicCandidate
        public StringBuffer(int capacity) {
            super(capacity);
        }
    
        /**
         * 根据String参数初始化
         */
        @HotSpotIntrinsicCandidate
        public StringBuffer(String str) {
            super(str.length() + 16); //先进行初始化
            append(str); //添加str
        }
    
        /**
         * StringBuffer中所有方法都有synchronized修饰,保证了线程安全
         * 每次操作都是对原有的byte数组操作,然后返回当前实例,从而实现了可变序列
         * 几乎所有方法都是调用父类的方法逻辑,再加上synchronized实现,比如下面的append
         */
        @Override
        @HotSpotIntrinsicCandidate
        public synchronized StringBuffer append(String str) {
            toStringCache = null;  //清空缓存
            super.append(str);
            return this; //返回this实例
        }
    
    
        // 覆写的toString方法,每次都是new一个String对象,如果toStringCache不为空,则直接用toStringCache构造String对象,否则进行数组copy
        @Override
        @HotSpotIntrinsicCandidate
        public synchronized String toString() {
            if (toStringCache == null) {
                return toStringCache =
                        isLatin1() ? StringLatin1.newString(value, 0, count)
                                : StringUTF16.newString(value, 0, count);
            }
            return new String(toStringCache);
        }
    
        /**
         * 自定义序列化字段,即序列化只序列化数组里面的属性
         * ObjectStreamField类型数组serialPersistentFields定义需要被自动序列化的字段,
         * 而且一旦定义了这个属性,那么就不会识别原本默认的可序列化字段,例如非static和非transitent字段。
         */
        private static final java.io.ObjectStreamField[] serialPersistentFields =
                {
                        new java.io.ObjectStreamField("value", char[].class),
                        new java.io.ObjectStreamField("count", Integer.TYPE),
                        new java.io.ObjectStreamField("shared", Boolean.TYPE),
                };
    
        /**
         * 自定义序列化:
         * 在序列化过程中,如果被序列化的类中定义了writeObject 和 readObject 方法,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法(利用反射实现),
         * 进行用户自定义的序列化和反序列化。
         * 如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。
         * 用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。
         */
        private synchronized void writeObject(java.io.ObjectOutputStream s)
                throws java.io.IOException {
            java.io.ObjectOutputStream.PutField fields = s.putFields();
            char[] val = new char[capacity()];
            if (isLatin1()) {
                StringLatin1.getChars(value, 0, count, val, 0);
            } else {
                StringUTF16.getChars(value, 0, count, val, 0);
            }
            //自定义序列化三个字段
            fields.put("value", val);
            fields.put("count", count);
            fields.put("shared", false);
            s.writeFields();
        }
    
        private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
            java.io.ObjectInputStream.GetField fields = s.readFields();
            //反序列化只获取value 和 count
            char[] val = (char[])fields.get("value", null);
            initBytes(val, 0, val.length);
            count = fields.get("count", 0);
        }
    

    三 StringBuilder源码解析

    StringBUilder与StringBuffer基本一样,只是自我实现没有保证线程安全以及自定义序列化字段的一些区别

        // 默认byte数组初始化为16
        public StringBuilder() {
            super(16);
        }
    
        public StringBuilder(int capacity) {
            super(capacity);
        }
    
        /**
         * 被@HotSpotIntrinsicCandidate标注的方法,在HotSpot中都有一套高效的实现,该高效实现基于CPU指令,
         * 运行时,HotSpot维护的高效实现会替代JDK的源码实现,从而获得更高的效率。
         */
        @HotSpotIntrinsicCandidate
        public StringBuilder(String str) {
            super(str.length() + 16);
            append(str);
        }
    
        @Override
        @HotSpotIntrinsicCandidate
        public StringBuilder append(String str) {
            super.append(str); //调用父类方法
            return this;
        }
    
        //自定义序列化直接序列化
        private void writeObject(java.io.ObjectOutputStream s)
                throws java.io.IOException {
            s.defaultWriteObject();
            s.writeInt(count);//序列化 count,实际占用长度
            char[] val = new char[capacity()];
            if (isLatin1()) {
                StringLatin1.getChars(value, 0, count, val, 0);
            } else {
                StringUTF16.getChars(value, 0, count, val, 0);
            }
            s.writeObject(val); // 序列化 char数组
        }
    
        private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            count = s.readInt();
            char[] val = (char[]) s.readObject();
            initBytes(val, 0, val.length);
        }
    
    

    四 总结

    • StringBuffer相比String来说,性能更高,因为不用每次去生成一个String实例,尤其是for循环中
    • StringBuilder性能会更好,他与StringBuffer都是继承了一样的父类,区别是各自的实现不同,一个线程安全,一个非线程安全
    • String适用于少量的字符串操作的情况
    • StringBuilder适用于单线程下在字符缓冲区进行大量操作的情况
    • StringBuffer适用多线程下在字符缓冲区进行大量操作的情况
  • 相关阅读:
    Saltstack
    搭建中小规模集群之rsync数据同步备份
    Python开发【第七篇】:面向对象二
    批量管理
    inotify
    Python开发【第六篇】:面向对象
    网络文件系统NFS
    Linux基础介绍【第九篇】
    Linux基础介绍【第八篇】
    Linux基础介绍【第七篇】
  • 原文地址:https://www.cnblogs.com/houzheng/p/12177643.html
Copyright © 2011-2022 走看看