Java常碰到的關鍵字詳解

關鍵字:html

  • final finalize finally
  • throws和throw
  • static關鍵字的做用
  • abstract和 interface
  • super和 this
  • synchronize和 volatile
  • String、StringBuffer、StringBuilder

1. final、finalize、finally對比java

(1)性質不一樣api

  • final爲關鍵字;
  • finalize爲方法;
  • finally爲爲區塊標誌,用於try語句中;

(2)做用不一樣數組

  • final:用於標識常量的關鍵字,final標識的關鍵字存儲在常量池中(在這裏final常量的具體用法將在下面進行介紹);final定義的變量值不可變,方法不可覆寫,類不可繼承。
  • 定義變量:一旦初始化(聲明處或構造函數中)便不可改變。對基本類型是其值不可變,對引用類型是引用不可變;(String天生就是final的)
  • 定義方法:1)使用final定義的方法,不容許覆寫,認爲其功能知足要求無需擴展時;2)容許編譯器將全部對此方法的調用轉化爲inline(行內機制),便可以將此方法直接複製在調用處,而不是進行例行的方法調用(保存斷點、壓棧),能夠提升效率。但若是過多的話,會形成代碼膨脹,反而會影響效率,慎用。
  • 定義類:沒法被繼承,這也就意味着此類在一個繼承樹中是一個葉子類;類成員是否是final均可以。
  • finalize:方法在Object中進行了定義,用於在對象「消失」時,由JVM進行調用用於對對象進行垃圾回收,相似於C++中的析構函數;用戶自定義時,用於釋放對象佔用的資源(好比進行I/0操做);
  • finally{}:用於標識代碼塊,與try{}進行配合,是異常處理模型的補充,不論try中的代碼執行完或沒有執行完(這裏指有異常),該代碼塊之中的程序一定會進行;不可單獨使用,在一個try...catch...finally語句塊中最多隻有一個finally;通常用來維護對象的內部狀態,清理非內存資源。

 

2. throws和throw對比  (Java中throws和throw的區別講解安全

(1)使用位置不一樣多線程

  • throw位於方法體內部,能夠做爲單獨語句使用;
  • throws位於方法頭部的參數列表後面,不能單獨使用;

(2)內容不一樣app

  • throw拋出一個具體的異常對象,並且只能是一個;
  • throws聲明拋出的異常類,能夠同時聲明多個;

(3)做用不一樣jvm

  • throw用於在程序中拋出異常,一旦執行說明必定有異常拋出,由方法體內部語句處理異常;
  • throws用於聲明在該方法內可能拋出的異常類,若是拋出了異常,由該方法的調用者處理,層層上拋;

總結:函數調用時,若是須要向上層拋出異常,就必須在函數頭部顯式地聲明(throws Exception1, Exception2)異常類型;若是僅須要在方法體內部處理異常,方法體內部可自行處理該異常,thorw拋出具體的異常實例(catch(Exception1 e){...})。函數

3. static關鍵字的做用性能

    static關鍵字可用來修飾屬性、方法、代碼塊,目的是把對象相關的變成類相關的,即:不加static的成員是對象相關的,歸單個對象全部;加static修飾的成員是類成員,能夠經過類名直接調用,歸全部對象全部。

static修飾的成員變量和成員方法習慣上稱爲靜態變量和靜態方法,能夠直接經過類名來訪問,訪問語法爲:

  • 類名.靜態方法名(參數列表…)
  • 類名.靜態變量名

(1)static修飾屬性(類變量、靜態變量)

  • 被static修飾的變量,叫靜態變量或類變量,可經過類名直接訪問;沒有被static修飾的變量,叫實例變量。
  • 靜態變量爲本類全部對象共享;實例變量只屬於單個對象。
  • 靜態變量在內存中只有一個拷貝,在類加載時被建立和初始化,JVM只爲其分配一次內存(節省內存)。類加載過程只進行一次,所以靜態變量也只會被建立一次;實例變量在建立對象時被初始化,在內存中有多個拷貝,每建立一個對象就會爲其分配一次內存,各實例變量間互不影響(靈活)。

        因此通常在須要實現如下兩個功能時使用靜態變量:

            1)在對象之間共享值時;2)方便訪問變量時

(2)static修飾方法(靜態方法)

  • static修飾的方法,叫靜態方法,可經過類名直接訪問,爲本類全部對象共享;
  • 靜態方法不能訪問本類的非靜態成員(包括實例變量和方法,由於非靜態則和特定的對象關聯,就不能全類共享了),可是非靜態方法能夠訪問靜態成員(ofcourse,靜態成員全類共享);
  • 靜態方法中不能出現this和super關鍵字(由於this是指向當前對象,super.成員名調用父類成員);
  • 由於static方法獨立於任何實例,所以static方法必須被實現,而不能是抽象的abstract;
  • 子類覆蓋父類的靜態方法時,只能依然覆蓋爲靜態方法(一日static終生static),可是沒有多態。

        Java中main方法必須爲static的緣由:

            在類加載時沒法建立對象,而靜態方法能夠不經過對象調用,因此在類加載時能夠經過main方法入口運行程序。

(3)static修飾代碼塊(初始化塊、靜態代碼塊)

    格式: static{...}

    static代碼塊也叫靜態代碼塊,是在類中獨立於類成員的static語句塊,能夠有多個,位置能夠隨便放,它不在任何的方法體內,JVM加載類時會執行這些靜態的代碼塊,若是static代碼塊有多個,JVM將按照它們在類中出現的前後順序依次執行它們,每一個代碼塊只會被執行一次。

初始化總結(靜態變量->實例變量->按聲明初始化->執行構造方法)

    1)首次使用某個類時,JVM查找相應的類文件並加載(Java只有在必要時纔會逐步載入相應的類文件)

    首先爲全部的靜態變量分配存儲空間並初始化爲默認值(全局變量),而後按照聲明靜態變量時指定的初始化動做的順序,以及靜態初始化塊中的語句在類定義中出現的順序依次執行。這些靜態的初始化動做只會在其所屬類的類文件加載時執行一次。

    2)類文件加載完畢後,若是須要建立類的對象,則進行以下初始化動做

    JVM爲全部的實例變量分配足夠的存儲空間並初始化爲默認值(局部變量);而後按聲明實例變量時指定初值的初始化動做和實例初始化塊中的語句在類中出現的順序依次執行,以後再調用相應的構造方法。

4. abstract和 interface對比

    abstract class和interface是支持抽象類定義的兩種機制。正是因爲這兩種機制的存在,才賦予了Java強大的面向對象能力。abstract class和interface之間在對於抽象類定義的支持方面具備很大的類似性,區別:

抽象類(Abstract Class):

    (1)只能做爲其餘類的基類,不能被實例化(new);

    (2)抽象類中的成員是否是abstract無所謂,並非必須的。(能夠有抽象成員,也能夠沒有任何抽象成員)

    (3)抽象類不能同時是final的。抽象的老是但願被繼承,而final類不可被繼承。final和abstract不可同時存在。

    (4)非抽象類繼承抽象類,必須覆蓋其全部的抽象成員。抽象類繼承抽象類,能夠不覆蓋全部的抽象成員。

    (5)抽象類容許被聲明

接口(interface):

    接口的本質是一種特殊的抽象類,用來描述系統對外提供的全部服務。

    (1)接口中,全部方法都是公開、抽象的:public abstract。(都必須被繼承)

    (2)接口中,全部屬性都是公開、靜態、常量:public static final,且必須賦初值。(全部實現類共享且不可改變)

    接口老是但願被實現被訪問的,所以全部成員都必須是公開的(public),確保外界能夠訪問。接口僅僅描述系統能夠作什麼,但不指明如何去作,具體操做由實現類完成,所以方法都是abstract的,都必須被繼承;接口不涉及任何的實現細節,所以無構造方法,接口不能被實例化;無變量,只有靜態常量(static final),由於要被全部的實現類共享;類的繼承只能單繼承,可是接口能夠一次實現多個,用「,」隔開。

5. super和 this對比

super:

    super能夠理解爲是指向本身父類對象的一個指針,指的是離本身最近的一個父類。

用法:

  • super.成員名(變量名或者方法名):顯式調用父類的同名成員,固然成員不能是private的(不容許子類訪問)。由於當子類和父類存在同名成員時,由於子類成員優先級更高,此時會隱藏父類的相應成員。
  • super(參數列表);:調用父類的構造函數,注意super語句必定要放在函數體的第一條 :

this:

    this能夠理解爲指向當前對象自身的一個指針,即當前正在執行本方法的那個對象實例。位於函數體內部。

用法:

  • this.成員名:引用成員變量。由於函數參數或者函數中的局部變量和成員變量同名的話,成員變量被屏蔽,此時要訪問成員變量則須要使用「this.成員變量」的方式引用。
  • this(參數列表);:調用本類中參數表一致的另外一個構造函數,注意應做爲構造函數中的第一條語句。

引用構造函數時:

    super(參數):調用父類中的某一個構造函數(應該爲構造函數中的第一條語句)。this(參數):調用本類中另外一種形式的構造函數(應該爲構造函數中的第一條語句)。

    this和super都無需聲明。

6. synchronize和 volatile對比

(1)做用範圍:volatile僅能使用在變量級別;synchronized則可使用在變量、方法、和類級別;

(2)volatile本質是在告訴jvm當前變量在寄存器(工做內存)中的值是不肯定的,須要從主存中讀取;synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住。

(3)volatile不會形成線程的阻塞;synchronized可能會形成線程的阻塞。

(4)volatile只能在線程內存和主內存之間同步一個變量的值,而synchronized則同步在線程內存和主內存之間的全部變量的值,經過鎖住和釋放監聽器來實現。

(5)volatile標記的變量不會被編譯器優化;synchronized標記的變量能夠被編譯器優化

(6)顯然,synchronized在性能上將比volatile更加有所消耗

(7)volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則能夠保證變量的修改可見性和原子性

7. String、StringBuffer、StringBuilder對比

(1)可變與不可變

  String類中使用字符數組保存字符串,以下就是,由於有「final」修飾符,因此能夠知道string對象是不可變的。

    private final char value[];

  StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,以下就是,可知這兩種對象都是可變的。

    char[] value;

(2)是否多線程安全

  String中的對象是不可變的,也就能夠理解爲常量,顯然線程安全

  AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操做,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,因此是線程安全的。看以下源碼:

public synchronized StringBuffer reverse() {

    super.reverse();

    return this;

}

public int indexOf(String str) {

    //存在 public synchronized int indexOf(String str, int fromIndex) 方法

    return indexOf(str, 0);       

}

  StringBuilder並無對方法進行加同步鎖,因此是非線程安全的

 (3)StringBuilder與StringBuffer共同點

  StringBuilder與StringBuffer有公共父類AbstractStringBuilder(抽象類)。

  抽象類與接口的其中一個區別是:抽象類中能夠定義一些子類的公共方法,子類只須要增長新的功能,不須要重複寫已經存在的方法;而接口中只是對方法的申明和常量的定義。

  StringBuilder、StringBuffer的方法都會調用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer會在方法上加synchronized關鍵字,進行同步。

  最後,若是程序不是多線程的,那麼使用StringBuilder效率高於StringBuffer。

關於String、StringBuffer、StringBuilder

參考轉載:http://www.cnblogs.com/xudong-bupt/p/3961159.html

                 http://www.cnblogs.com/xudong-bupt/p/3961159.html

Java中String、StringBuffer、StringBuilder區別與理解

1、先比較String、StringBuffer、StringBuilder變量的HashCode值

使用System.out.println(obj.hashcode())輸出的時對象的哈希碼,
而非內存地址。在Java中是不可能獲得對象真正的內存地址的,由於Java中堆是由JVM管理的不能直接操做。 
只能說此時打印出的Hash碼錶示了該對象在JAVA虛擬機中的內存位置,
Java虛擬機會根據該hash碼最終在真正的的堆空間中給該對象分配一個地址. 
可是該地址 是不能經過java提供的api獲取的

String變量鏈接新字符串會改變hashCode值,變量是在JVM中「鏈接——斷開」;
StringBuffer變量鏈接新字符串不會改變hashCode值,由於變量的堆地址不變。
StringBuilder變量鏈接新字符串不會改變hashCode值,由於變量的堆地址不變。

小結:哈希碼相同的變量,其內容不必定相同;內容向同變量,哈希碼不必定相同;

public class Buffer_HashCode01 {
    public static void main(String[] args) {

        String str1="學海無涯苦做舟";
        System.out.println("String 的 str1的hascode"+str1.hashCode());
        str1=str1+"人間正道是滄桑";      //注意此str1的存儲地址已發生變化
        System.out.println("String 的 str1的hascode"+str1.hashCode());
        System.out.println(str1);
        StringBuffer sb1=new StringBuffer("弟子規");
        System.out.println("原來StringBuffer 的 hascode:"+sb1.hashCode());
        StringBuffer sb2=sb1.append("聖人教");    //注意sb1和sb2指向同一個地址
        System.out.println("添加字符串後StringBuffer 的 hascode:"+sb2.hashCode());
        sb2.insert(6,"海納百川");
        StringBuilder sb=new StringBuilder("這顯然是上半年");
        System.out.println("改變前StringBuilder變量的hashCode值"+sb.hashCode());
        sb.append("哦是的啊");
        System.out.println("改變後StringBuilder變量的hashCode值"+sb.hashCode());
    }
}

    結果:
        String 的 str1的hascode-2054942391
        String 的 str1的hascode895667206
        學海無涯苦做舟人間正道是滄桑
        原來 StringBuffer 的 hascode:1311053135
        添加字符串後StringBuffer 的 hascode:1311053135
        改變前StringBuilder變量的hashCode值118352462
        改變後StringBuilder變量的hashCode值118352462

 

2、比較String、StringBuffer、StringBuilder性能(僅在繁複操做)

String類因爲Java中的共享設計,在修改變量值時使其反覆改變棧中的對於堆的引用地址,因此性能低。

StringBuffer和StringBuilder類設計時改變其值,其堆內存的地址不變,避免了反覆修改棧引用的地址,其性能高。

其中StringBuilder是專門相似於StringBuffer類的非線性安全類,即StringBuffer是線性安全的,適合於多線程操做;

StringBuilder是線性不安全的,適合於單線程操做,其性能比StringBuffer略高。

public class Xing_Neng_SSS01 {
    public static void main(String[] args) {

        long begin1 = System.currentTimeMillis();
        String str = "";
        for(int i=0;i<10000;i++){
            str = str+i;
        }

        long end1 = System.currentTimeMillis();
        long time1 = end1 - begin1;
        System.out.println("一、String + time="+time1);   

        long begin2 = System.currentTimeMillis();
        String str2 = "";
        for(int i=0;i<10000;i++){
            str2 = str2.concat(i+"");
        }

        long end2 = System.currentTimeMillis();
        long time2 = end2 - begin2;
        System.out.println("二、String concat time="+time2); 

        long begin3 = System.currentTimeMillis();
        StringBuffer str3 = new StringBuffer();
        for(int i=0;i<10000;i++){
            str3.append(""+i);
        }

        long end3 = System.currentTimeMillis();
        long time3 = end3 - begin3;
        System.out.println("三、StringBuffer time="+time3);  

        long begin4 = System.currentTimeMillis();
        StringBuilder str4 = new StringBuilder();
        for(int i=0;i<10000;i++){
            str4.append(""+i);
        }

        long end4 = System.currentTimeMillis();
        long time4 = end4 - begin4;
        System.out.println("四、StringBuilder time="+time4);
    }
}

    結果:
        一、String + time=241
        二、String concat time=92
        三、StringBuffer time=4
        四、StringBuilder time=2

 

3、String共享設計

當String使用引號建立字符串時,會先去字符串池中找,找到了就返回,找不到就在字符串池中增長一個而後返回,這樣因爲共享提升了性能。

 而new String()不管內容是否已經存在,都會開闢新的堆空間,棧中的堆內存也會改變。

下面是==來比較地址是否相等。

public class String_Equals01 {
    public static void main(String[] args) {

        String str1="學海無涯苦做舟人間正道是滄桑";
        String str11=str1;
        String str12="學海無涯苦做舟人間正道是滄桑";
        String str13=new String("學海無涯苦做舟人間正道是滄桑");

        System.out.println("String 的 str1 的hascode"+str1.hashCode());
        System.out.println("String 的 str11的hascode"+str11.hashCode());
        System.out.println("String 的 str12的hascode"+str12.hashCode());
        System.out.println("String 的 str13的hascode"+str13.hashCode());
        System.out.println("str1==str11  "+(str1==str11));
        System.out.println("str1==str12  "+(str1==str12));
        System.out.println("str1==str13  "+(str1==str13));
    }
}

    結果:
        String 的 str1 的hascode895667206
        String 的 str11的hascode895667206
        String 的 str12的hascode895667206
        String 的 str13的hascode895667206
        str1==str11 true
        str1==str12 true
        str1==str13 false
相關文章
相關標籤/搜索