1. 程式人生 > >JDK原始碼之基礎類

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
    }