StringBuilder源码解析

1.StringBuilder是线程不安全的,里面的char[]是可变的,增删改操作都是依赖System.arraycopy 函数来实现的。StringBuilder会默认构造16个长度,当后面修改到超过时会自动扩容到(char[].length+ 1) * 2,这就是比String效率高的原因,不用像String一样容量不够就重新构造对象,StringBuilder会自动扩容。

2.自定义StringBuilder代码:

// 一些具体功能实现,两个实现类 StringBuilder和StringBuffer
abstract class AbstractStringBuilder {
    char value[];
    // 并不等于value.length 当前 有效字符串的长度
    int count;

    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
    public AbstractStringBuilder append(String str) {
        if (str == null)
            str = "null";
        int len = str.length();
        if (len == 0)
            return this;
        int newCount = count + len;// 两个字符串之和
        if (newCount > value.length) // char[] 空间不够了
            expandCapacity(newCount);
        // 把 str 用 System.arraycopy 复制到value中
        str.getChars(0, len, value, count);
        count = newCount;
        return this;
    }

    void expandCapacity(int minimumCapacity) {
        // 扩大 (value.length + 1) * 2
        int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
            newCapacity = minimumCapacity;
        }
        // 用System.arraycopy 来复制 value并 扩大newCapacity长度
        value = Arrays.copyOf(value, newCapacity);
    }

    public AbstractStringBuilder delete(int start, int end) {
        int len = end - start;// 要删除字符串的长度
        if (len > 0) {
            /**
             * 把要删除的字符串之后的的字符串 ,前移到删除的位置, 就表示 删除了字符串,
             */
            System.arraycopy(value, start + len, value, start, count - end);
            count -= len; // 有效长度 减去删除的长度
        }
        return this;
    }
    public AbstractStringBuilder insert(int offset, String str) {
        int len = str.length();
        int newCount = count + len;
        if (newCount > value.length)// 容量不够 ,扩容
            expandCapacity(newCount);
        // 把 insert位置的len个长度 空出来
        System.arraycopy(value, offset, value, offset + len, count - offset);
        // 把str拷贝到 value中
        str.getChars(value, offset);
        count = newCount;
        return this;
    }
}
//StringBuilder类
class MyStringBuilder extends AbstractStringBuilder {
    public MyStringBuilder() {
        super(16);// 默认构造 16 个长度的char数组
    }

    // 添加字符串,父类实现
    public MyStringBuilder append(String str) {
        super.append(str);
        return this;
    }
    // 删除
    public MyStringBuilder delete(int start, int end) {
        super.delete(start, end);
        return this;
    }
    // 插入
    public MyStringBuilder insert(int offset, String str) {
        super.insert(offset, str);
        return this;
    }
    // 重新构造一个String
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }
}

分析了几个重要方法,都是System.arraycopy来操作char[] 实现的。
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Pinpoint 的 DefaultSqlParser 是用于解析 SQL 语句的工具。它主要用于解析 SQL 语句中的表名、列名、条件语句等信息。解析过程中会涉及到正则表达式的使用。 下面是 DefaultSqlParser 源码解析: ``` public class DefaultSqlParser implements SqlParser { private static final String[] EMPTY_STRING_ARRAY = new String[0]; @Override public ParsedSql parse(String sql) { if (sql == null) { return new ParsedSql(EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, false, false); } String newSql = SqlParsingUtils.removeComments(sql); newSql = SqlParsingUtils.replaceQuotationMark(newSql); List<String> parameters = new ArrayList<>(); StringBuilder parameterBuilder = new StringBuilder(); Set<String> tables = new LinkedHashSet<>(); Set<String> columns = new LinkedHashSet<>(); boolean inSingleQuoteString = false; boolean inDoubleQuoteString = false; boolean inParameter = false; int length = newSql.length(); for (int i = 0; i < length; i++) { char c = newSql.charAt(i); boolean isLast = (i + 1) == length; if (inSingleQuoteString) { if (c == '\'') { if (isLast || newSql.charAt(i + 1) != '\'') { inSingleQuoteString = false; } else { i++; } } } else if (inDoubleQuoteString) { if (c == '\"') { if (isLast || newSql.charAt(i + 1) != '\"') { inDoubleQuoteString = false; } else { i++; } } } else if (inParameter) { if (c == '?') { parameters.add(parameterBuilder.toString().trim()); parameterBuilder.setLength(0); inParameter = false; } else { parameterBuilder.append(c); } } else { if (c == '\'') { inSingleQuoteString = true; } else if (c == '\"') { inDoubleQuoteString = true; } else if (c == '?') { inParameter = true; } else if (c == ' ') { // skip } else if (c == ',') { // skip } else if (Character.isLetter(c) || c == '_') { // table name or column name int j = i + 1; for (; j < length; j++) { if (!(Character.isLetterOrDigit(newSql.charAt(j)) || newSql.charAt(j) == '_')) { break; } } String word = newSql.substring(i, j); String lowerCaseWord = word.toLowerCase(); if (SqlParsingUtils.TABLE_HINTS.contains(lowerCaseWord)) { // skip table hints } else if (SqlParsingUtils.QUERY_HINTS.contains(lowerCaseWord)) { // skip query hints } else if (SqlParsingUtils.TABLE_KEYWORDS.contains(lowerCaseWord)) { // table name i = j - 1; for (; j < length; j++) { if (newSql.charAt(j) == ' ' || newSql.charAt(j) == '\t') { continue; } else if (newSql.charAt(j) == '(') { i = j; break; } else { tables.add(word); break; } } } else { // column name columns.add(word); i = j - 1; } } } } return new ParsedSql(tables.toArray(new String[tables.size()]), columns.toArray(new String[columns.size()]), !parameters.isEmpty(), inParameter); } } ``` 其中,parse() 方法接收一个 SQL 语句作为参数,并返回 ParsedSql 对象,该对象包含解析后的表名、列名、参数等信息。 在解析过程中,首先会移除 SQL 语句中的注释和替换引号,然后遍历 SQL 语句的每个字符,根据不同的字符型进行相应的处理。具体来说: - 如果当前字符在单引号字符串中,则跳过; - 如果当前字符在双引号字符串中,则跳过; - 如果当前字符是问号,则表示当前字符为参数,将 inParameter 标记设置为 true,并将参数添加到 parameters 集合中; - 如果当前字符是空格或逗号,则跳过; - 如果当前字符是字母或下划线,则表示当前字符为表名或列名。在往后遍历时,如果遇到空格或括号,则表示当前字符为表名,否则为列名; - 如果当前字符不属于上述任何一种型,则跳过。 在解析过程中,还需要注意以下几点: - 如果 SQL 语句中出现了嵌套的单引号或双引号,则需要特殊处理; - 如果 SQL 语句中出现了注释,则需要移除; - 如果 SQL 语句中出现了参数,则需要将 inParameter 标记设置为 true,并将参数添加到 parameters 集合中; - 如果 SQL 语句中出现了表名或列名,则需要将其添加到 tables 或 columns 集合中。 最后,将解析得到的表名、列名、参数等信息封装到 ParsedSql 对象中,并返回即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值