1.2、java.lang(精讀部分)

我們都知道java.lang是java的核心包。
現在我們開始閱讀lang包的一些東西。

Object

Object類是java中所有類的父類(超類),所有的對象(包括數組)都實現了這個類的方法

構造方法只有一個默認的無參構造方法

接下來,我們一個個,看看其中的方法;

1、clone

protected native Object clone() throws CloneNotSupportedException;

如果類沒有實現Cloneable接口。 就算重寫了clone方法的子類也可以拋出一個異常以指示實例無法克隆。 (CloneNotSupportedException

所以的數組是默認實現了Cloneable接口的

以ArrayList爲例,下面的一般情況下,三個都會輸出true;

ArrayList<String> x = new ArrayList<>();
System.out.println(x.clone().getClass() == x.getClass());
System.out.println(x.clone() != x);
System.out.println(x.clone().equals(x));

雖說,clone方法是這個實例的一個克隆。 但是,可以看到,他們並不是完全相等的。(第二個輸出)

2、equals

public boolean equals(Object obj)

equals方法在非空對象引用上實現的等價關係有:自反性;對稱性;傳遞性;

對於任何非空的x,x.equals(null)應該返回false
對於任何非空的x和y ,當且僅當x和y引用相同的對象( x == y具有值true )時,該方法返回true 。

請注意,無論何時重寫該方法,通常需要重寫hashCode方法,以便維護hashCode方法的通用合同,該方法規定相等的對象必須具有相等的哈希碼。

3、getClass
jdk中描述:getClass方法返回此Object的運行時類。 返回的類對象是被表示類的static synchronized方法鎖定的對象。

何謂運行時類,即內存中實實在在存在的類

這個方法一般在 反射 中應用的比較多。

4、其他一些方法

返回值 方法 描述
int hashCode() 返回對象的哈希碼值。
void notify() 喚醒正在等待對象監視器的單個線程。
void notifyAll() 喚醒正在等待對象監視器的所有線程。
String toString() 返回對象的字符串表示形式。
void wait() 導致當前線程等待,直到另一個線程調用該對象的 notify()方法或 notifyAll()方法。
void wait(long timeout) 導致當前線程等待,直到另一個線程調用 notify()方法或該對象的 notifyAll()方法,或者指定的時間已過。
void wait(long timeout, int nanos) 導致當前線程等待,直到另一個線程調用該對象的 notify()方法或 notifyAll()方法,或者某些其他線程中斷當前線程,或一定量的實時時間。


《8種基本數據類型 》

byte

在這裏插入圖片描述
byte類是final類。也就是說它是不可以被繼承的

還有就是經典的“127和128”的問題了(圖懶得換了…MAX_VALUE = 127

java中,byte是一個字節佔八位。

12701111111)127(01111111)
在加一,出現什麼情況?計組原理中說過第一位是符號位(0正1負)
在這裏插入圖片描述
第一個:int+byte;
第二個:byte+byte(+=的特性)越界:

在計算機中,由於原碼的表示不便,進行運算需要判斷其正負極其絕對值的大小。所以,在計算機中,通常都是採用補碼形式。 正整數的補碼與原碼形式相同,正數的原碼反碼補碼相同,負數的補碼=反碼(反碼=原碼的符號位不變其他位取反)+1

12701111111)127(01111111)+100000001)1(00000001)得到1000000010000000

1000000010000000,按照計算,這個不應該是-0嗎?爲什麼是-128呢?

首先灌輸一個新的概念叫,模
什麼是“模”,想象日常使用的鐘表,它可以顯示0~12點的時間,假設現在是2點鐘,請用手動撥動時針的方式將時間減4小時,你會怎麼做?

有兩種方式:
逆時針將時針撥4小時,
順時針將時針撥8(12-4)小時

這裏要講的是第二種方式,爲什麼順時針撥12-4也可以達到和正常思維的第一種方式一樣的位置。12就是模。同樣的,如果是十進制的兩位數,80-10 和 80+90在不考慮百位數的基礎上都是70。這裏的90就是100-10得來的,這種情況下100就是模模就好比是一個極限,在它的範圍內,兩個相加等於模的數互爲補數,還是舉100的例子90和10, 55和45,68和32,互爲補數在模的範圍內做減法,可以將“X-Y”的減法變更爲“X+Y的補數“的加法,當然前提是不考慮百位數

思考題,上面舉的例子是大數減小數,那麼如果是小數減大數會怎麼樣呢?如果是10-80,結果應該是-70,但如果按照10+(100-80),結果是30。而很明顯-70和30不是一回事,這裏也沒有百位數的問題,這種情況應該怎麼破?

當初的那些先賢們想出來的辦法很簡單,就是把這兩個數直接劃上等號,正好順便解決了負數的表達方式。再來仔細看看這兩個數的關係:-70絕對值的補數就正好是30所以在計算機中,負數的表達方式就是它絕對值的補數但是問題又來了,看起來這個解決方式很完美了,但別忘了,30他已經代表了正數的30了,現在又要用來代表負數的-70,誰知道它出現的時候到底是代表哪個數?

爲了解決這個問題,需要給這套規則劃定一個範圍,原來是0~99的正數,現在既然要用部分正數來代替負數了,那就要規定一個範圍來使得一個數只代表一個含義,正好一人一半,0~49這個區間就代表正數,50~99的區間就用來代表各自補數的負值,例:98就代表 -2

第三步,現在回到二進制的計算機世界8位二進制數一共可以表示2的8次方,256個數,即0~255 (別忘了0也要佔一位的),他們的極限就是256,即256是8位二進制數的模 ,應該不難理解吧,同上十進制的兩位數0~99的模是100。還是用二進制來說明清楚,8位二進制能表示的數的極限是1 1 1 1 1 1 1 1, 就是255,在這基礎上加0 0 0 0 0 0 0 1,出現了進一位 即 1 0 0 0 0 0 0 0 0這個1 0 0 0 0 0 0 0 0就是8位二進制數的模,256同樣按照第二步講的邏輯,一半的數0~127,代表其正數本身,另一半的數 128~255,代表其補數的負值,即“-1~-128”的區間。 而 “X-Y”的減法 就用 “X+Y的補數” 的加法來表示,完美! 唯一需要注意的事情是任何計算的輸入值和輸出結果值都需要嚴格遵守-128~127的範圍,一旦溢出就會報錯。這也就是我們在編程裏強調的爲什麼 byte+byte還得是byte,int+int還得是int,數據溢出問題也是每一個程序員都需要注意的問題。這樣一說是不是可以理解-128的補碼是怎麼來的了吧? 他就是256-|-128|=128二進制的128是不是就是1 0 0 0 0 0 0 0 ?

最終問題,那書和老師爲什麼要用原碼,反碼來講補碼 ?空穴來風,未必無因那是因爲計算機就是這樣求負數的補碼的,我們在鍵盤上敲一個負數的時候,計算機要把它用補碼的形式存儲下來,還記得上面我們講的補碼是怎麼來的嗎?模-絕對值,這是不是個減法公式?但計算機沒有減法邏輯,我們費了那麼大的勁搞了一套補碼的規則就是爲了用加法來替代減法,但爲了實現這麼套規則,卻跨不過一個坎,就是把負數計算成補碼仍然是需要減法邏輯的。怎麼辦呢,那些偉大的先賢們 (膜拜)就想出了這麼個辦法:首位不變,其餘位取反後,再加一

參考自:在8位二進制中,-128 沒有原碼、反碼形式,那麼它的補碼是怎麼計算出來的?還是約定的? - Simon Cao的回答 - 知乎

別忘了,object類是所有類的超類,所以,byte中還重寫了hashcode,tostring等方法。

再看看下面的例子
在這裏插入圖片描述
int型是32位的,前面還要補23個0,然後取後八位的結果是00000000
在這裏插入圖片描述
當a=257的時候,輸出就會是1,因爲100000001,取後八位。我這樣理解,其實,是一個新的循環,類似於上面的模的概念。

那麼 256+128~256+256之間的數應該是負數
在這裏插入圖片描述
思考:400去掉一個256等於144,0~127爲正,128~255爲負數,144-256(模)=-112

使用byte時,一定要主要,值得範圍 [-128,127]

short

java中short是2個字節,16位,所以,216/2=327682^{16}/2=32768,所以,在這裏插入圖片描述

Integer

Integer類是基本數據類型int的包裝器類,是抽象類Number的子類,位於java.lang包中。

Integer類在對象中包裝了一個基本類型int的值,也就是每個Integer對象包含一個int類型的字段。

在這裏插入圖片描述
一些靜態字段:

[static int] MAX_VALUE:值爲 231-1 的常量,它表示 int 類型能夠表示的最大值。2147483647

[static int] MIN_VALUE:值爲 -231 的常量,它表示 int 類型能夠表示的最小值。-2147483648

[static int] SIZE: 用來以二進制補碼形式表示 int 值的比特位數。

[static Class] TYPE:表示基本類型 int 的 Class 實例。

[static int] BYTES:返回int值所佔的字節數。

equals方法

public boolean equals(Object obj) {
   if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

在Integer類中,“==”用來比較對象地址是否相同,並且Integer類重寫了equals(Object obj)方法,在equals(Object obj)方法中,會先判斷參數中的對象obj是否是Integer類型的對象,如果是則判斷值是否相同,值相同則返回true,值不同則返回false,如果obj不是Integer類的對象,則返回false。需要注意的是:當參數是基本類型int時,編譯器會給int自動裝箱成Integer類,然後再進行比較。

toString方法

public static String toString(int i) {
    if (i == Integer.MIN_VALUE)
        return "-2147483648";
    int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
    char[] buf = new char[size];
    getChars(i, size, buf);
    return new String(buf, true);
}

//其中stringSize和getChars如下:
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

static void getChars(int i, int index, char[] buf) {
  int q, r;
    int charPos = index;
    char sign = 0;

    if (i < 0) {
        sign = '-';
        i = -i;
    }

    // Generate two digits per iteration
    while (i >= 65536) {
        q = i / 100;
    // really: r = i - (q * 100);
        r = i - ((q << 6) + (q << 5) + (q << 2));
        i = q;
        buf [--charPos] = DigitOnes[r];
        buf [--charPos] = DigitTens[r];
    }

    // Fall thru to fast mode for smaller numbers
    // assert(i <= 65536, i);
    for (;;) {
        q = (i * 52429) >>> (16+3);
        r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
        buf [--charPos] = digits [r];
        i = q;
        if (i == 0) break;
    }
    if (sign != 0) {
        buf [--charPos] = sign;
    }
}

toString返回該Integer值得String對象

r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...

針對這行,做個解釋:<<:左移運算(在數字沒有溢出的前提下,對於正數和負數,左移一位都相當於乘以2的1次方,左移n位就相當於乘以2的n次方。),>>:右移運算(右移一位相當於除2,右移n位相當於除以2的n次方。)

移位運算符的效率是比普通的乘法(除法)效率高的

具體是怎麼做的,是二進制數的轉換移位,不再贅述

將字符串(不能含有其他字符,構造方法Integer(String s),也同理)轉爲數字的方法是:

public static int parseInt(String s) throws NumberFormatException {
 	return parseInt(s,10);
}
public Integer(String s) throws NumberFormatException {      		
	this.value = parseInt(s, 10);
}
//其中調用的是另外一個重載方法。給的默認radix爲10。具體的自行查看
//可以看出,integer構造方法本質上和parseint方法是一樣的。

在這裏插入圖片描述

long

long類型的值範圍-9223372036854775808 ,9223372036854775807

Long(String s)
parseLong(String s)
equals()
toString()

都是和integer有異曲同工之妙的

boolean

Boolean 類有以下兩種構造形式:

Boolean(boolean boolValue);
Boolean(String boolString);

其中 boolValue 必須是 true 或 false(其他的編譯會出錯),boolString 僅含有 字符串 true(不區分大小寫),那麼新的 Boolean 對象爲 true;否則爲 false。

忽略大小寫,在源碼中也是有體現的:如下:
在這裏插入圖片描述在這裏插入圖片描述

Character

有一個簡單的構造方法:
Character(char value) :構造一個新分配的 Character 對象,用以表示指定的 char 值。

Character 類在對象中包裝一個基本類型 char 的值。Character 類型的對象包含類型爲 char 的單個字段。

此外,該類提供了幾種方法,以確定字符的類別(小寫字母,數字,等等),並將字符從大寫轉換成小寫,反之亦然。

Double

double的值範圍:4.9E-324 ,1.7976931348623157E308
這裏的思路也是從,類的定義>>字段>>構造方法>>其他方法
在這裏插入圖片描述
一些靜態字段:
在這裏插入圖片描述
構造方法

Double(double value)
構造一個新分配的 Double 對象,它表示基本的 double 參數。

Double(String s)
構造一個新分配的 Double 對象,表示用字符串表示的 double 類型的浮點值。

其他一些方法提供 double和String的互轉,也提供了其他一些處理 double 時有用的常量和方法。

Float

和double類異曲同工。


String

基本介紹:

String代表字符串。 Java程序中的所有字符串文字(例如"abc" )都被實現爲此類的實例。 String是類嗷,不是基本數據類型。

字符串不變; 它們的值在創建後不能被更改。 字符串緩衝區支持可變字符串。 因爲String對象是不可變的,它們可以被共享。

String類包括用於檢查序列的各個字符的方法,用於比較字符串,搜索字符串,提取子字符串以及創建將所有字符翻譯爲大寫或小寫的字符串的副本。

在這裏插入圖片描述
實現了序列化的接口和Comparable接口

Comparable接口:該接口對實現它的每個類的對象強加一個整體排序。 這個排序被稱爲類的自然排序 ,類的compareTo方法被稱爲其自然比較方法 。

一些靜態變量:

/** The value is used for character storage. */
private final char value[];

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

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;

/**
* Class String is special cased within the Serialization Stream Protocol.
*
* A String instance is written into an ObjectOutputStream according to
* <a href="{@docRoot}/../platform/serialization/spec/output.html">
* Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];

一些構造方法:
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述

進一步理解:
private final char value[];,由這個變量我們可以看出,爲什麼String類的對象一旦創建就不可變更的原因就是,因爲字符串都是通過這個final修飾的char數組保存的(在內存中其實是字符串常量池中),字符串的每一個字符都是char類型的,char是基本類型。

不知道有沒有人對第二個構造方法的方法體有疑問?

public String(String original) {
    this.value = original.value;//怎麼賦值的?
    this.hash = original.hash;
}

這裏的參數“original”,他本身也是String類的一個對象,而original.value是,對象點屬性的基本使用。original.value,實際上是創建一個String類的一個對象“original”的value,把這個value,賦值給String類的value

String str = “abc”;
相當於:
char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);

一些常用的方法

endsWith(String suffix) 
測試此字符串是否以指定的後綴結尾。

concat(String str) 
將指定的字符串連接到該字符串的末尾。 

charAt(int index) 
返回 char指定索引處的值。

compareTo(String anotherString) 
按字典順序比較兩個字符串。 

contains(CharSequence s) 
當且僅當此字符串包含指定的char值序列時才返回trueequals(Object anObject) 
將此字符串與指定對象進行比較。 

equalsIgnoreCase(String anotherString) 
將此 String與其他 String比較,忽略案例注意事項。

indexOf(String str) 
返回指定子字符串第一次出現的字符串內的索引。 

isEmpty() 
返回 true如果,且僅當 length()0split(String regex) 
將此字符串分割爲給定的 regular expression的匹配。 

length() 
返回此字符串的長度。 

substring(int beginIndex, int endIndex) 
返回一個字符串,該字符串是此字符串的子字符串。

trim() 
返回一個字符串,其值爲此字符串,並刪除任何前導和尾隨空格。
//去掉所有的空白可以用replaceAll(" ","");

replaceAll(String regex, String replacement) 
用給定的替換替換與給定的 regular expression匹配的此字符串的每個子字符串。

StringBuffer

StringBuffer ,線程安全,可變的字符序列。 它的父類是AbstractStringBuilder

stringbuffer類
在這裏插入圖片描述
構造方法

    public StringBuffer() {
        super(16);
    }
    public StringBuffer(int capacity) {
        super(capacity);
    }
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

//父類
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

注意value是沒有用final修飾的。這也是字符串長度可變的原因
在這裏插入圖片描述

注意value是沒有用final修飾的。這也是字符串長度可變的原因

通過閱讀源碼知道:StringBuffer的字符串是通過調用父類的append方法,來把字符存起來的,而父類的append方法(其中一個,有很多構造方法)代碼如下:

public AbstractStringBuilder append(String str) {
   if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

getchars方法,value就是之前貼出來的那個char數組
在這裏插入圖片描述
return this 就是返回當前對象的引用(就是實際調用這個方法的實例化對象)

本例中,父類其實就返回了AbstractStringBuilder類的一個實例化對象
子類(代碼如下)中返回的是StringBuffer 對象,而且我們可以觀察到,這個append方法是加了關鍵字 synchronized,以此亦可以說明,stringbuff是線程安全的,其他所有的append方法都是有這個關鍵字的

@Override
 public synchronized StringBuffer append(String str) {
     toStringCache = null;
     super.append(str);
     return this;
 }

return this 的進一步理解測試

public class OCReading {
    private String a;
    public void setA(String str){
        this.a = str;
    }
    public String getA(){
        return this.a;
    }
    public OCReading get(String string){
        setA(string);
        return this;
    }
    public static void main(String[] args) {
        OCReading ocReading = new OCReading();
        OCReading ocReading1;
        ocReading1 = ocReading.get("sjt");
        System.out.println(ocReading1.getA());//out:sjt
    }
}

其他說明(摘自jdk1.8):

一般情況下,如果某人是指的一個實例StringBuffer ,則sb.append(x)具有相同的效果sb.insert(sb.length(), x) 。

每當涉及源序列(例如從源序列追加或插入)的操作發生時,該類僅在執行操作的字符串緩衝器上進行同步,而不在源上。 請注意,雖然StringBuffer被設計爲可以安全地從多個線程併發使用,但如果構造函數或append或insert操作被傳遞通過線程共享的源序列,則調用代碼必須確保該操作具有一致且不變的視圖在操作期間的源序列。 呼叫者通過使用不可變的源序列,或者不跨線程共享源序列,可以在呼叫期間持有鎖來滿足這一點。

每個字符串緩衝區都有一個容量。 只要字符串緩衝區中包含的字符序列的長度不超過容量,就不必分配新的內部緩衝區數組。 如果內部緩衝區溢出,則會自動變大。

除非另有說明,否則將null參數傳遞給null中的構造函數或方法將導致拋出NullPointerException

StringBuilder

StringBuilder和stringbuffer大同小異,最重要的一個區別就是,stringbuffer線程安全(有鎖),stringbuilder沒有鎖,是線程不安全的

Math

Math類包含執行基本數字運算的方法,如基本指數,對數,平方根和三角函數。

Math是final類。

兩個基本屬性和一個構造方法

 /**
     * Don't let anyone instantiate this class.
     */
    private Math() {}

    /**
     * The {@code double} value that is closer than any other to
     * <i>e</i>, the base of the natural logarithms.
     */
    public static final double E = 2.7182818284590452354;

    /**
     * The {@code double} value that is closer than any other to
     * <i>pi</i>, the ratio of the circumference of a circle to its
     * diameter.
     */
    public static final double PI = 3.14159265358979323846;

E是自然對數的基數,PI是圓周率(圓周長與其直徑的比率)

這個類的方法基本上是和數學相關的計算:

  • 絕對值 abs
  • 正弦,餘弦,正切,還有他們三個的反值
  • 對數,指數
  • 比較大小,計算 和 積 差 商
  • 獲取隨機數,四捨五入

Enum

枚舉類:Java語言中所有枚舉類型的公共基類,枚舉類型是Java 5中新增特性的一部分,它是一種特殊的數據類型,之所以特殊是因爲它既是一種類(class)類型卻又比類類型多了些特殊的約束。

唯一的一個構造方法:

我們無法調用此構造函數。 它由編譯器響應枚舉類型聲明發出的代碼使用。

我們自己寫的枚舉類,編譯器在編譯的時候回生成對應的final類來繼承該基類。

name - - 此枚舉常量的名稱,它是用於聲明它的標識符。
ordinal - - 這個枚舉常數的序數(它在枚舉聲明中的位置,其中初始常數被分配爲零的序數)。

protected Enum(String name, int ordinal) {
    this.name = name;
    this.ordinal = ordinal;
}

在這裏插入圖片描述

更多請參考大佬博文:https://blog.csdn.net/javazejian/article/details/71333103

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