修飾符是用於限定類型以及類型成員申明的一種符號,可用於修飾類、變量和方法,分為訪問修飾符和非訪問修飾符。訪問修飾符控制訪問權限,不同的訪問修飾符有不同的權限范圍,而非訪問修飾符則是提供一些特有功能。
訪問權限修飾符
訪問修飾符有四個,權限從大到小:public、protected、default、private ,訪問范圍如下:
- public 本類、同包、子類和全局(只要導入包就能訪問)
- protected 本類、同包和子類
- default 本類、同包(當類、方法和變量不添加權限修飾符時,默認使用)
- private 本類(類的內部)
package com.A; public class Demo01 { public String a = "公共的"; protected String b = "受保護的"; String c = "默認的"; private String d = "私有的"; //在類的內部可以隨意訪問數據域 public void test() { System.out.println(a + b + c + d); } }
繼承Demo01類, 父類中private修飾的d屬性無法被繼承。
package com.A; public class Son extends Demo01 { //訪問繼承自父類的數據域 public static void main(String[] args) { System.out.println(new Son().a); System.out.println(new Son().b); System.out.println(new Son().c); } }
不同包的子類,默認權限c屬性和私有屬性d無法繼承。
package com.B; import com.A.Demo01; public class Son_b extends Demo01{ //子類方法中打印從父類Dmeo01中繼承來的數據域 public void test() { System.out.println(new Son_b().a); System.out.println(new Son_b().b); } }
通過以上的代碼實例即可看出不同的訪問修飾符所能控制的范圍是不同的。
非訪問修飾符
非訪問修飾符有很多,最經常用到的當屬static和final了,除此之外還有許多非訪問修飾符會在下面一一介紹。
static
- 調用靜態變量和靜態方法時,只需要類名.靜態變量/靜態方法。使用對象也可以調用,但這樣做不規范。
- static能修飾的類只有內部類,也叫作靜態內部類,地位等同於外部類的靜態變量。
- static不能修飾局部變量,因為作用域僅限於所處的塊,而static本身的功能相違背且不允許。
- 在靜態方法中,例如main()方法,不能使用this和super關鍵字來訪問實例變量和調用方法,若要調用實例變量,則需要實例化一個對象。
final
final可修飾變量、方法和類,一旦被final修飾,該變量就不能改變值或是改變其引用。編譯器會檢查代碼,試圖更改時編譯器會報錯。
final注意點:
- final修飾的方法不能被重寫,final修飾的類也不允許被繼承,final修飾的類為不可變類。
- 修飾變量時,都是當成常量來用,通常和static關鍵字配合使用,而且常量最好使用全大寫。
為什么要和static一起使用呢?通過兩種常量來說明一下兩者區別
public final int A = 10; //A為實例常量 public final static int B = 100; //B為靜態常量
//實例常量伴隨對象的創建而生成,運行完成后即被銷毀,頻繁創建和銷毀非常浪費內存空間。 //而靜態常量(全局常量)隨着類的初始化就存儲在JVM開辟的常量池中,使用之后也不會被回收,直到程序結束。 //所以如果有數字或者字符串被多次反復使用時,可以用final static來修飾。
final修飾的優點
- final關鍵字可以提高性能,JVM和Java應用都會緩存final變量。
- final修飾后,編譯時就進行靜態綁定,不需要在運行時在動態綁定。
- final變量可以安全的在多線程環境下進行共享,而不需要額外的同步開銷。 使用final關鍵字,JVM會對方法、變量及類進行優化。
- final修飾類則是不可變類。不可變類的實例創建后,該實例的內容無法被改變。String是不可變類的代表。
- 不可變類有很多好處,譬如它們的對象是只讀的,可以在多線程環境下安全的共享,不用額外的同步開銷等等。
abstract
- abstract只能修飾類和方法,稱為抽象類和抽象方法,定義抽象類的唯一目的就是子類對該類進行擴展重寫,抽象方法必須實現。
- 一個類不能同時被 abstract 和 final 修飾,因為理念沖突。
- 抽象類不能實例化對象,因為抽象方法沒有方法體,所以抽象類實例無法調用方法,實例化無意義。
- 若類中包含抽象方法,則該類必須聲明為抽象類,否則將出現編譯錯誤。
- 抽象類中能同時聲明抽象方法和普通方法,相當於普通類和接口的中間層,類似半成品。
synchronized
修飾方法作為同步方法,則在同一時間該方法只能被一個線程所訪問,別的線程將阻塞。修飾方法可以隱式傳入同步監視器對象。作為同步代碼塊,示例如下:
//需要顯式傳入同步監視器對象 synchronized(Object obj) { //需要同步的代碼... }
volatile
transient
運用在對象序列化中,當對某個對象進行序列化(轉換成二進制存儲在硬盤中),有些私有信息不想被序列化時,就用transient去修飾,transient表示透明化的,作用就如其名,序列化時就會忽略掉該信息。注意:類要實現序列化需要實現Serializable接口,該接口沒有任何方法,僅僅作為序列化的標識。