【小白的java成長系列】——String類的深入分析(基於源碼)

接着前面面向對象來說吧~今天來說說String類。。其實String類也包含很多面向對象的知識的~

首先來問一個問題:我們在開發過程中,如果要使用一個類的話,就要創建對象,這句話沒什麼問題吧~在實際開發的時候確實是這樣的,只有創建了對象才能真正的去使用一個普通的類,我們一般創建對象,幾乎所有的類創建對象都是要通過new關鍵字來創建的~

問題就來了。。爲什麼我們的String可以直接寫成String str = "abc";這樣子呢?

當然String類也可以通過new來創建對象的。。。

其實也不難,我們看到它的源碼說明就知道的:

 * Strings are constant; their values cannot be changed after they
 * are created. String buffers support mutable strings.
 * Because String objects are immutable they can be shared. For example:
 * <p><blockquote><pre>
 *     String str = "abc";
 * </pre></blockquote><p>
 * is equivalent to:
 * <p><blockquote><pre>
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * </pre></blockquote><p>

進入String的源碼,最前面就能看到上面的文字的:大致的意思是,String的對象值其實是通過char[]數組來存儲的,String str = "abc";等同於char data[] = {'a', 'b', 'c'};  String str = new String(data);明白清晰了吧~

1、String類的定義:

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

問題:在開發過程中,我們可以繼承String類嗎?

答案:不行的,我們看定義就知道,String的定義使用了final修飾符,定義爲了終結類,所以String是不能做擴展的。

implements:這個關鍵字是用來表示實現接口作用的,意思就是Serializable、Comparable和CharSequence都是接口的。

查看接口源碼:

Comparable<T>  :表示比較器作用,<T>採用了java泛型的形式

Serializable:

public interface Serializable {
}

我們可以看到Serializable接口裏面啥都木有,那爲什麼我們要實現這個接口呢?這個接口的作用是啥呢?

作用:java類的序列化,至於序列化,後面會詳細介紹。其實Serializable是java的一個標記接口,什麼叫標記接口?Serializable只是作爲一個標記的作用,關於它具體的功能和作用交給了JVM底層去實現了,實現了這個接口,只是通知JVM,String這個類可以序列化。

CharSequence:表示字符序列吧~這個沒啥好說的,String的存儲方式依賴於字符序列的~


2、屬性

    private final char value[];	//String值就是存儲在value[]上的

    private int hash; // Default to 0  表示hash值,


    private static final long serialVersionUID = -6849794470754667710L;//序列化作用

    private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];//序列化作用

我們只要瞭解String類的屬性就可以,幾乎都不會用到的,因爲都是定義成了private,私有化了~

3、構造方法

這裏也只說幾個特殊的,一般在開發過程中也不會用到構造方法的,因爲很少使用new來創建String對象的,都是直接使用String str = "abc";這樣子的形式。。

在面試過程中,很多面試官會問到String str = new String("abc");這個創建了幾個對象?至於答案和解釋,這邊就不做介紹了,想知道的就去網上查找了解~這個涉及到底層的內存問題的,描述起來篇幅會很長的~

    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }
從上面可以看到,String兩個核心就是value和hash的,這兩個值基本決定了String對象的。

    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }
這個是通過底層數組拷貝的方式創建,其實底層使用的是System.arrayCopy()這個方法,此方法使用了native修飾的,底層是由C/C++來實現的,其實就是一個拷貝的作用

public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
    }
這個表示的是通過字節(byte)來構造字符串,其實底層的實現也是通過System.arrayCopy()這個方法的。

其他的基本也沒什麼好說的,瞭解一下就可以的。我們可以看到有些構造使用了@Deprecated註解,這個註解表示的過時,不推薦使用這個方法的

4、常用方法

    public int length() {	//返回字符串長度
        return value.length;
    }

	public boolean isEmpty() {//判斷字符串是不是爲空
        return value.length == 0;
    }

	public char charAt(int index) {//字符串中的某個字符,index表示字符的位置
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

	public byte[] getBytes() {//獲取字節數組
        return StringCoding.encode(value, 0, value.length);
    }

	public boolean equals(Object anObject) {//字符串比較,我們知道基本類型的比較都是通過==來做比較的,
						//但是字符串需要使用此方法來做比較的

我們主要來驗證一下==和equals方法

package me.javen.oop;

public class StringDemo {

	public static void main(String[] args) {
		String str1 = "hello" ;					// 直接賦值
		String str2 = new String("hello") ;		// 通過new賦值
		String str3 = str2 ;					// 傳遞引用
		System.out.println("str1 == str2 --> " + (str1==str2)) ;	// false
		System.out.println("str1 == str3 --> " + (str1==str3)) ;	// false
		System.out.println("str2 == str3 --> " + (str2==str3)) ;	// true
		
		//以下通過equals方法
		System.out.println("str1 equals str2 --> " + (str1.equals(str2))) ;	// true
		System.out.println("str1 equals str3 --> " + (str1.equals(str3))) ;	// true
		System.out.println("str2 equals str3 --> " + (str2.equals(str3))) ;	// true
	}

}
此外還有一個比較方法也用得比較多:

public boolean equalsIgnoreCase(String anotherString) {//不分大小寫比較

	public boolean startsWith(String prefix) {//判斷字符串是不是以prefix開頭
	public boolean endsWith(String suffix) {//判斷字符串是不是以suffix結尾
	public int hashCode() {//獲取字符串的hash值
	public int indexOf(String str) {//獲取字符str的起始位置,-1表示沒有這個字符
        return indexOf(str, 0);
    }

	public String substring(int beginIndex, int endIndex) {//截取字符串beginIndex表示起始位置,endIndex表示結束位置
	public String replaceAll(String regex, String replacement) {//字符串替換replacement替換regex

	public String[] split(String regex) {//分隔字符串,regex表示分隔符

	public String toLowerCase() {//將字符串全部轉換爲小寫
	public String toUpperCase() {//將字符串全部轉換爲大寫
	
	public String trim() {//去掉首尾空格,字符中間的空格不能去掉

	public static String valueOf(Object obj) {//將obj轉換成字符串,這個可以傳遞任意類型,比如數字,字符,浮點數等等

此外還有其他的很多方法,這邊就不列舉出了,學習者可以通過代碼的方式去使用這些個方法,列舉出來的表示開發中常用的方法~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章