JDK原始碼之基礎類
一 概述
1、Java,是一套語言規範,例如規定了變數如何定義、控制語句如何寫等,提供基本的語法規範。JDK是java自帶的一套呼叫元件,是對基本java語法規範的進一步封裝,jdk中都是使用java基本的語法來寫的,使用JDK能夠更好的使用java。
2、在整個JDK API中,大約包含1200個包,包名主要有三種:java、javax和org。其中以java開頭的包名是JDK的基礎語言包,以javax開頭的屬於JDK擴充套件包(其中x是extend的簡寫),而以org開頭的則是第三方組織提供的功能包(org是organization的簡寫)。而在JDK API中還包含了一些以com.sun開頭的包名,這些是SUN公司提供的一些功能包,由於這些包中的類隨著JDK版本的更改變化很大,不具備相容性,所以未在標準的JDK API文件中進行公開。
3、rt.jar檔案是java執行時類庫,是我們用到最多的基礎類庫,包括java.lang,java.io,java.net,java.util等。
java.lang
:Java語言包,這個包下的檔案不需要顯式import。包括:Object類,資料型別相關的類(String,Long,Byte),Class類,執行緒相關類Thread,異常類Throwable,等。
java.io
:I/O操作相關的類。包括:檔案類File,FileReader,FileWriter,輸入輸出流InputStream/OutputStream,等。
java.net
:網路相關類。包括:http連線類HttpURLConnection,socket類,等。
java.util
:工具類。包括:資料結構相關的類ArrayList、Hashmap,日期類Date,隨機數類Random,等。
4、java native方法:不由java實現的方法,一般這些方法都是很底層,跟平臺結合緊密,或者使用java實現效能很差。
二 Object
1、Object類是java中所有類的父類,所有類預設繼承Object。這也就意味著,Object類中的所有公有方法也將被任何類所繼承。如果,整個java類體系是一顆樹,那麼Object類毫無疑問就是整棵樹的根。
Object類中的方法如下:
2.equals()方法:判斷指定的物件和傳入的物件是否相等。 ”==“和equals()兩者比較,前者比較的地址是否相等(常量比值),即是否同一個物件,後者比較的是值是否相等
三 Class
1、先複習幾個概念:
類:事物特徵的抽象,可以理解為模板,是事物特徵的定義。可以建立物件。
物件:是一個具體的事物實體,由類建立的。
2、Class類也是一個抽象的事物定義,也是類的一種,同String類以及自己定義的類是一樣的。只是名字和class關鍵字高度相似。Java是大小寫敏感的語言。
3、Class類的物件不能像普通類一樣,以 new shapes() 的方式建立,Class類的物件只能由JVM建立,因為這個類沒有public建構函式。
4、一個類的多個物件只會有一個Class物件。每個類都有一個Class物件。
5、基本的 Java 型別(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也都對應一個 Class 物件。
6、每個陣列屬於被對映為 Class 物件的一個類,所有具有相同元素型別和維數的陣列都共享該 Class 物件。
7、使用Class.forName(),載入一個類到記憶體中,使用newInstance()建立類。newInstance()方法呼叫預設構造器(無引數構造器)初始化新建物件。
8、java裡面任何類都要裝載在虛擬機器上才能執行。forName就是裝載類用的(new是根據載入到記憶體中的類建立一個例項,要分清楚)。 至於什麼時候用,可以考慮一下這個問題,給你一個字串變數,它代表一個類的包名和類名,你怎麼例項化它?A a = (A)Class.forName("pacage.A").newInstance();這和A a = new A();是一樣的效果。
9、jvm在裝載類時會執行類的靜態程式碼段,要記住靜態程式碼是和類繫結的,類裝載成功就表示執行了你的靜態程式碼了,而且以後不會再執行這段靜態程式碼了。
10、從JVM的角度看,我們使用關鍵字new建立一個類的時候,這個類可以沒有被載入。但是使用newInstance()方法的時候,就必須保證:這個類已經載入和這個類已經連線了。而完成上面兩個步驟的正是Class的靜態方法forName()所完成的,這個靜態方法呼叫了啟動類載入器,即載入 java API的那個載入器。現在可以看出,newInstance()實際上是把new這個方式分解為兩步,即首先呼叫Class載入方法載入某個類,然後例項化。這樣分步的好處是顯而易見的。我們可以在呼叫類的靜態載入方法forName時獲得更好的靈活性,提供給了一種降耦的手段。
11、用最簡單的描述來區分new關鍵字和newInstance()方法的區別:
newInstance: 弱型別。低效率。只能呼叫無參構造。
new: 強型別。相對高效。能呼叫任何public構造。
public class People {
private String name;
private int age;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public void say() {
System.out.println("Hello world!");
}
public String showInfo() {
return "My name is " + this.name;
}
}
public class ClassTest {
public static void main(String[] args) {
try {
//先載入類,再建立例項,等同於People tim = new People();
People tim = (People) Class.forName("com.tim.People").newInstance();
tim.say();
// 獲取tim這個物件的類描述資訊,
// 可以獲取:類的構造方法,已經宣告的欄位、方法,獲取類或者方法的註解,獲取類的包名、父類,以及判斷類是否是陣列、是否是列舉、是否是介面
// 主要針對不清楚類的內部資訊時,使用該方法獲取
Class peopleClass = tim.getClass();
Field[] peopleField = peopleClass.getDeclaredFields();//獲取類的欄位
for (Field field : peopleField) {
System.out.println(field.getName());
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
四 字串類
1.String類(字串常量)→subString是擷取字串的方法。length是字串長度的方法。int compare(String s)是比較兩個字串的大小,相等返回0,不相等返回不相等字元編碼值的差。
2.StringBuffer類(字串可以改變,執行緒安全)→append(String str)在字串末尾追加一個字串。char charAt(int index)返回指定下標的字元。intcapacity()表示返回字串緩衝區容量。
3.StringBuilder類(字串可以改變,執行緒不安全,因此效能比 StringBuffer 好)
要點:StringBuffer是執行緒同步的,StringBuilder是非同步;對不經常變化的字串使用String即可。經常變化、正在拼裝的字串不用String。若是全域性變數,可能多執行緒引用,使用StringBuffer;若是區域性變數,單執行緒使用,推薦StringBuilder。 (瞭解同步和非同步就能理解他們的執行緒區別)
五 拆箱裝箱
java語言認為一切皆物件。 8個基本資料型別野應該具備對應的物件。 通過封裝類可以把8個基本型別的值封裝物件進行使用。 從JDK1.5開始,java允許把基本型別的值直接賦值給對應的封裝類物件。
裝箱和拆箱 →本質是基本型別和其封裝類之間能自動進行轉換
定義:裝箱指的是把基本資料型別值轉換成封裝物件,即把棧中的資料封裝成物件存放到堆中的過程。拆箱是裝箱的反過程。裝箱操作是資料由棧道堆,拆箱是資料由堆到棧。
//首先要明確一點,物件之間的==是比較記憶體地址,常數之間的比較是數值比較。
public static void main(String[] args) {
Integer num1 = new Integer(100);
Integer num2 = new Integer(100);
System.out.println(num1 == num2);//false,因為這兩個物件是獨立建立的,有自己的記憶體空間和地址。
Integer num3 = 100;
Integer num4 = 100;
System.out.println(num3 == num4);//true,常數之間比較數值。
Integer num5 = 128;
Integer num6 = 128;
System.out.println(num5 == num6);//false,自動裝箱成物件,但是超過了預設的快取範圍,同第一個。如果是127就是true。
Integer num7 = 100;
Integer num8 = new Integer(100);
System.out.println(num7 == num8);//false,兩個物件之間比較記憶體地址,不同的是num7通過自動裝箱呼叫valueOf方法,指向快取的100,而num8是指向自己記憶體空間裡的100.
int num9 = 1000;
Integer num10 = new Integer(1000);
System.out.println(num9 == num10);//true,Integer物件和int比較時(其它7種也一樣),Integer會自動拆箱(intValue方法)成為int,變成兩個數值比較。
Integer num11 = 100;
System.out.println(num9 == num11);//true,num11通過自動裝箱呼叫valueOf方法指向快取中的100,比較的時候快取中的100物件自動拆箱成為數值100.
//特別的Double,Float是沒有快取機制的,因為即使是-128~127之間的浮點數接近無窮大。
Float f1 = 1f;
Float f2 = 1f;
System.out.print(f1==f2);//false
//但Double,Float仍然滿足拆箱裝箱機制(一共8種)。即Double、Float物件與double、float比較時,會自動拆箱成為基礎型別,變成兩個數值的比較
float f3 = 1000.0f;
Float f4 = new Float(1000.0f);
System.out.print(f3==f4);//true
}