Object、String、StringBuffer、StringBuilder源码探究(基于JDK1.8)

Object类源码

Object是所有类的父类,意味着接下来看的所有的类都会继承或者重写Object类中的方法。逐一看一下Object类中的所有方法。

源码中类的介绍:Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.

本地方法关键字 Native:用于修饰方法,表示该方法不是java编写的,是底层系统语言已经编写好了的,一般是C/C++编写。

在Object类的静态代码块中调用了私有的本地方法。因为被private修饰,说明其他类继承不了,是Object类所特有的,与日常开发无光,不深入去了解。

registerNatives(),用于注册一组本地方法,这些方法提供了Object类的基本操作的本地实现。这些本地方法通常是由JVM的实现提供的,用于提高执行效率或与底层系统进行交互。

 getclass():返回运行时,实例的类对象。注意泛型擦除。

  • 泛型擦除:编译器在编译时会去掉泛型的信息,生成一个桥接方法保持与原方法的兼容性。
  • // 编译前
    Pair<String> pair = new Pair<>("Hello", "World");
    
    // 编译后(类型擦除)
    Pair pair = new Pair("Hello", "World");
    
    
    
    // 编译前
    class Box<T> {
        T value;
        void setValue(T value) { this.value = value; }
        T getValue() { return value; }
    }
    
    // 编译后(桥接方法)
    class Box {
        Object value;
        void setValue(Object value) { this.value = value; }
        Object getValue() { return value; }
    }

hashCode() :返回对象的哈希码值。一般会为不同的对象返回不同的整数。

  • Object类的equals()方法默认实现是比较对象的引用地址。
  • 当覆盖hashCode方法时需要同时覆盖equals方法
    • 在Java中,equalshashCode 方法之间存在一种约定,这个约定要求相等的对象必须具有相等的哈希码。这是因为在使用一些基于哈希表的数据结构时(例如 HashMapHashSet),哈希码用于快速定位对象在内部数据结构中的位置。

      如果两个对象被认为是相等的(根据 equals 方法的定义),那么它们的哈希码应该相同。因此,如果你覆盖了 equals 方法来定义对象的相等性,就需要确保相等的对象产生相同的哈希码。

      这样的一致性保证了在使用这些对象的哈希值作为键或集合元素时,能够正确地执行哈希表的操作,例如查找、插入和删除。

    • 基于hash结构的集合:HashMap、HashSet、Hashtable、LinkedHashMap、ConcurrentHashMap

equals():比较对象之间的等价关系。

  • Object类的equals()方法默认实现是比较对象的引用地址。
  • 当覆盖equals方法时需要同时覆盖hashCode方法。

clone():克隆一个对象

  • clone方法执行的是浅拷贝,即它创建了一个新实例并复制了原始对象的字段的内容,但字段中的对象引用仍然指向相同的对象。(说明两个对象会存在共享的部分)
    • 深拷贝:它创建一个新的对象,同时递归地复制该对象内部的所有可变对象,而不仅仅是复制引用。深拷贝确保克隆对象和原始对象的内部结构完全独立,对一个对象的修改不会影响到另一个对象。
  • 对象的类不实现 Cloneable 接口,调用 clone 方法将抛出此异常。子类也可以选择抛出此异常以表示该类的实例无法被克隆。

toString():返回对象的字符串表示形式。

  • Object类默认返回类名@16进制的哈希码值。

notify():唤醒等待线程

notifyAll():唤醒所有等待线程

wait():让当前线程进入等待状态

finalize():GC调用,在对象回收之前释放或者清理资源。

String类源码

属性:

  • private final char value[];
    • 很多方法操作数组就能获取结果
  • private int hash; // Default to 0
compareToIgnoreCase(String str):忽略大小写比较

静态内部类:CaseInsensitiveComparator实现Comparator接口,用与忽略大小写比较。

 public int compare(String s1, String s2) {
    int n1 = s1.length();
    int n2 = s2.length();
    int min = Math.min(n1, n2);
    for (int i = 0; i < min; i++) {
        char c1 = s1.charAt(i);
        char c2 = s2.charAt(i);
        if (c1 != c2) {
            c1 = Character.toUpperCase(c1);
            c2 = Character.toUpperCase(c2);
            if (c1 != c2) {
                c1 = Character.toLowerCase(c1);
                c2 = Character.toLowerCase(c2);
                if (c1 != c2) {
                    // No overflow because of numeric promotion
                    return c1 - c2;
                }
            }
        }
    }
    return n1 - n2;
}  

构造方法:这些构造方法都会返回一个char 类型的数组,赋值给value。

equals(Object anObject):

 先比较引用是否相等,如果相等显然相等。否则比较字符串的每一个字符。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
compareTo(String anotherString) :比较每一个字符

返回:用字符串本身字符减去要比较的字符串字符(参数)

public int compareTo(String anotherString) {
    int len1 = value.length;
    int len2 = anotherString.value.length;
    int lim = Math.min(len1, len2);
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        if (c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    return len1 - len2;
}

toLowerCase():转小写。

为什么其他方法是返回一个char数组赋值给value,而转大小写是new String对象?

修改了原字符串,与原先的字符串值不一样,又因为string 的value被finally修饰,所以只能new一个对象。 

public String toLowerCase(Locale locale) {
    if (locale == null) {
        throw new NullPointerException();
    }

    ......
    return new String(result, 0, len + resultOffset);
}
getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)

调用本地方法System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);将char数组复制到一个新的数组中。

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
    if (srcBegin < 0) {
        throw new StringIndexOutOfBoundsException(srcBegin);
    }
    if (srcEnd > value.length) {
        throw new StringIndexOutOfBoundsException(srcEnd);
    }
    if (srcBegin > srcEnd) {
        throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
    }
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

 toString()

public String toString() {
    return this;
}


//
private final char value[];

/** Cache the hash code for the string */
private int hash; // Default to 0

substring(int beginIndex)

public String substring(int beginIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    int subLen = value.length - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}

StringBuilder类源码

 StringBuilder继承AbstractStringBuilder

AbstractStringBuilder:

append(String str)

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    // 确保数组容量足够大,不够扩容:长度大小左移一位并加2
    ensureCapacityInternal(count + len);
    // 将str复制到value,String类源码介绍过
    str.getChars(0, len, value, count);
    // 得出count其实用于计算char数组长度
    count += len;
    return this;
}

// 为null char数组赋值null
private AbstractStringBuilder appendNull() {
    int c = count;
    ensureCapacityInternal(c + 4);
    final char[] value = this.value;
    value[c++] = 'n';
    value[c++] = 'u';
    value[c++] = 'l';
    value[c++] = 'l';
    count = c;
    return this;
}
append(StringBuffer sb)
public AbstractStringBuilder append(StringBuffer sb) {
    if (sb == null)
        return appendNull();
    int len = sb.length();
    ensureCapacityInternal(count + len);
    sb.getChars(0, len, value, count);
    count += len;
    return this;
}


// AbstractStringBuilder定义了getChars方法,内用与String类的getChars一样,调用native方法
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
    if (srcBegin < 0)
        throw new StringIndexOutOfBoundsException(srcBegin);
    if ((srcEnd < 0) || (srcEnd > count))
        throw new StringIndexOutOfBoundsException(srcEnd);
    if (srcBegin > srcEnd)
        throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}

append(boolean b) 、append(Object obj)

public AbstractStringBuilder append(boolean b) {
    if (b) {
        ensureCapacityInternal(count + 4);
        value[count++] = 't';
        value[count++] = 'r';
        value[count++] = 'u';
        value[count++] = 'e';
    } else {
        ensureCapacityInternal(count + 5);
        value[count++] = 'f';
        value[count++] = 'a';
        value[count++] = 'l';
        value[count++] = 's';
        value[count++] = 'e';
    }
    return this;
}


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

toString() :重写toString方法,返回一个new String对象

@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

StringBuffer类源码

StringBuffer与StringBuilder一样都继承AbstractStringBuilder,StringBufferr的方法基本上也是和StringBuilder一样调用父类的方法。

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值