天天看點

JavaSE學習筆記(9.Java中的修飾符)

1.Java關鍵詞:

Java有50個關鍵詞分别如下表:

JavaSE學習筆記(9.Java中的修飾符)

其中條件分支相關的有17個:if、else、do、while、for、continue、break、switch、case、throw、throws、try、catch、finally、goto(預留)、assert、return

包相關2個:import、package

類型相關10個:void、byte、char、short、int、long、boolean、float、double、enum

類相關的8個:new、class、extends、interface、implements、this、super、instanceof

修飾詞的有13個:private、protected、default、public、abstract、static、final、transient、const(預留)、native、strictfp、volatile、synchronized

2.修飾符分類:

2.1 private、protected、預設包通路描述符(省略)、public用于描述作用域:

1. 修飾外部類(包括普通類、枚舉類、抽象類、接口):隻可以使用public和預設描述符修飾!

                      public描述符:包外作用域及包内作用域,都可以通路類

                      預設描述符 : 包内作用域,可以通路類

2. 修飾類内成員(各種内部類、靜态非靜态成員方法及變量、構造器):可以使用public、protected、預設修飾符、private修飾!

                      public修飾符:包内外全局均可以通路!

                      protected修飾符:包内全作用域及包外子類内作用域可以通路!

                      預設修飾符:包内全作用域!

                      private修飾符:類内作用域!

Ps:

  • 類内成員作用域一定要小于類的作用域,因為類内成員一定不會被大于類作用域的作用域通路到!如預設作用域的類中的public修飾的成員,就不會被包外作用域通路到!
  • 類成員和非類成員并不會影響成員的作用域,僅僅影響成員的通路方式而已(類通路、執行個體通路)!
  • 抽象類中的抽象方法不可以是private屬性的,因為抽象方法需要重寫,private屬性的方法無法類外通路,無法重寫!
  • 當類有且隻有一個private屬性的構造器的時候,該類應該被final屬性修飾,因為該類無法在子類構造器中調用父類構造器,是以無法繼承!
  • 子類重寫父類方法的時候,作用域隻可以增大不可以變小
  • 接口中所有成員(類成員變量、抽象方法、default方法、static方法、各種内部類)都是public通路屬性,預設不填的編譯器會預設補充為public屬性!
  • 接口中的抽象方法,如果修飾作用域必須使用public屬性修飾,不可以使用其他修飾符!同時可以不寫,編譯器預設補充public、final、abstract修飾符!
  • 每一個Java檔案最多隻能有一個public屬性的類,并且這個類名必須要和檔案名一緻!同樣可以沒有public屬性的類,預設修飾符屬性的類可以有多個,類名可以不與檔案名一緻!

2.2 final修飾符:

1. 修飾外部類(普通類、枚舉類:編譯器自動添加):final修飾外部類的時候,隻能修飾普通類和枚舉類,不能修飾接口、抽象類;被final修飾的普通類和枚舉類不可以被繼承!

2. 修飾類内成員(非内部接口/抽象内部類的各種内部類、類成員和執行個體成員方法及變量):                                            

     2.1 内部類:final修飾内部類表示該内部類不可以被繼承; 此處主要注意局部内部類和匿名内部類的effectively final規則               

     2.2 類成員方法/執行個體成員方法:被修飾的方法在子類中不可以被重寫,靜态非靜态規則一緻!隻有當private和final同時修飾方法的時候,可以無視final修飾符,因為子類中沒有辦法通路繼承自父類的private屬性方法,不會存在二義性!

     2.3 類成員變量:final修飾類成員變量,表示該類成員變量一旦被初始化(初始化可以在定義時完成,也可以在初始化代碼塊中完成)後,即不可再被修改!

     2.4 執行個體成員變量:final修飾執行個體成員變量,表示該執行個體成員變量一旦被初始化(初始化可以在定義時完成;也可以在構造器中完成,當構造器存在嵌套調用的時候,隻能在最早被調用的構造器中定義)後,即不可再被修改!

Ps:final修飾類成員變量和執行個體成員變量的原則,變量值不随着執行個體建立而改變的均設計為final static屬性,在類建立的時候指派;變量随着執行個體建立而改變的(在構造方法中初始化不同值的情況)設計為final屬性!

3. 修飾局部變量:final修飾局部變量,表示該局部變量一旦被初始化(初始化可以在定義時完成,也可以在該局部變量使用前完成)後,即不可再被修改

4. 修飾形參:final修飾形參,表示該形參在方法内不可用改變引用指向或者值内容!

Ps:

  1. 當final修飾的變量在定義的時候初始化,并能夠在編譯的時候确定其值,則該變量會被編譯成為宏變量(常量值)!
  2. Java語言規範中,隻有final修飾符可以修飾形參,但final修飾符不參與形參類型是否一緻的判斷(隻有形參個數和形參類型參與判斷)!

2.3 static修飾符:

1. 修飾類内成員(靜态内部類、類成員方法和變量、類初始化塊):使得被修飾的内容隸屬于類,通過類進行通路及初始化!

Ps:類方法、類成員變量、内部類均可以繼承;類方法還可以被重寫!(說明子類中均具備父類的類成員)

很多地方通過類方法無法多态來描述類方法不可以重寫,但是個人認為最直接的說明問題的還是final修飾符,原本可以重寫的類方法,在父類中增加final修飾符,會導緻編譯報錯!

package Grpc_Test.GrpcProject;

public class Test 
{
	public static void main( String[] args )
	{
		
	}
	
	public static final void fun()
	{
		
	}
}

class TestSon extends Test
{
        //編譯報錯!!!
	public static void fun()
	{
		
	}
}
           

編譯器報錯說明:

JavaSE學習筆記(9.Java中的修飾符)

2.4 abstract修飾符:

1. 修飾外部類(隻能修飾抽象類和抽象枚舉類:編譯器自動添加;不能修飾接口、普通類):表示該類為抽象類,不可執行個體化,類中可以存在抽象方法!

2. 修飾類内成員(抽象方法、抽象内部類):

2.1 抽象方法:abstract修飾成員方法,表示該方法為抽象方法,不可以有方法體!抽象方法比較特殊,因為抽象方法沒有方法體,不能完成類方法通路!是以不能被static修飾;同時抽象類不能執行個體化,導緻這個方法有不是執行個體方法!

Ps:抽象方法隻有被子類繼承才有存在的意義,是以抽象方法不能被private修飾或者final修飾!

2.2 抽象内部類(靜态内部類、非靜态内部類、局部内部類):abstract不可以修飾匿名内部類,因為匿名内部類需要執行個體化!   

public abstract class TestAbstract {
		
	/*abstarct修飾靜态内部類*/
	public abstract static class inclass1
	{
		
	}
	
	/*abstract修飾非靜态内部類*/
	public abstract class inclass2
	{
		
	}
	
	public void fun()
	{
		/*abstract修飾局部内部類*/
		abstract class inclass3
		{
			
		}
	}
	
}
           

Ps:abstract不可以與final共存!!!

2.5 default修飾符:

隻作為接口中預設方法修飾符使用,不可以與static共存!!!較長的描述見JavaSE學習筆記(5.抽象類與接口)

2.6 transient修飾符(具體細節在序列化章節補充):

transient修飾類變量和成員變量,表示在序列化的時候,忽略該變量!

2.7 native修飾符(具展現實細節後面補充):

native隻能修飾方法,用作JNI(Java Native Interface);同樣native修飾的方法沒有方法體,表示通過Java調用C/C++實作的代碼(C/C++需要編譯成為DLL檔案,被Java加載調用)!

Ps:native實作過程:

  1、在Java中聲明native()方法,然後編譯;

  2、用javah産生一個.h檔案;

  3、寫一個.cpp檔案實作native導出方法,其中需要包含第二步産生的.h檔案(注意其中又包含了JDK帶的jni.h檔案);

  4、将第三步的.cpp檔案編譯成動态連結庫檔案;

  5、在Java中用System.loadLibrary()方法加載第四步産生的動态連結庫檔案,這個native()方法就可以在Java中被通路了。

2.8 strictfp修飾符:

修飾類(各種外部類、各種内部類包括枚舉)、成員方法、類方法、成員變量、類變量:用來訓示被修飾範圍内的Java的編譯器和運作環境完全按照浮點型規範IEEE-754來執行(Java的浮點運算是做過優化的)!

2.9 volatile修飾符(具體細節線程章節補充):

修飾線程共享變量(類變量、執行個體成員變量),保證變量的可見性、有序性:

1. 在JMM模型中,被volatile修飾的線程共享變量,不進行線程内資料緩存,會将線程本地變量記憶體值的改變迅速覆寫主記憶體中去,并将其他線程中的該變量記憶體的緩存設定為過期!進而完成線程A中的資料改變傳遞給線程B!當然不設定volatile就存在可緩存,可不緩存的歧義場景!

2.被volatile修飾的變量,會在一定規則的程度下禁止指令重排序優化!詳細規則見<Java中的volatile>

2.10 synchronized修飾符(具體細節線程章節補充):

1. 類内成員(修飾執行個體方法和類方法):修飾同步方法,如果該方法是執行個體方法則預設的同步螢幕為this;如果該方法為類方法則預設的同步螢幕為(xxx.class對象)!

2. 修飾同步代碼塊:表示修飾的代碼塊,在并發的時候需要通過搶占同步螢幕來獲得通路權限!

2.11 接口中修飾符使用限制:

1. 對于接口的通路權限修飾符隻能是public和預設包通路權限!

2. 接口中的成員隻能有,類常量(final static)、類方法(static)、預設方法(default)、抽象方法(abstract)、内部類(内部接口、内部枚舉、抽象内部類、内部類);注意接口中無構造器和初始化塊!

3. 接口中的所有成員都是public屬性,可以明确定義,也可以省略,編譯器自動補充!

4. 接口中的類常量隻能是public static final屬性,同樣這三個修飾符都可以省略,編譯器可自動補充!

5. 接口中的抽象方法隻能是public abstract屬性,同樣對于沒有方法體的方法,可以省略這兩個修飾符,編譯器可自動補充!

6. 接口中的各種内部類隻能是public static屬性,同樣這兩個修飾符可以省略,編譯器可自動補充!

3.修飾符對成員方法重寫的影響:

子類方法被認定為父類方法的重寫方法原則:方法名相同、方法參數類型相同(作用域修飾符、static、final都不能作為判斷依據)!!!

3.1 作用域修飾的影響:為了保證通過父類可以順利調用子類中的繼承重寫的父類方法;必須保證子類重寫父類的方法的時候,修飾符作用域一定大于父類方法作用域修飾符!否則當方法被認定為是重寫方法的時候,則會報錯!!!

public class Test 
{
	public void fun()
	{
		
	}
}

class TestSon extends Test
{
	/*編譯報錯*/
	private void fun()
	{
		
	}
}
           

3.2 static修飾符的影響:靜态方法可以重寫靜态方法,執行個體方法可以重寫執行個體方法;一旦子類方法被認定為重寫方法,存在靜态方法與執行個體方法交叉重寫的情況,編譯會報錯!!!

Ps:靜态方法可以被子類重寫,但是不能構成多态!即通過子類通路的靜态方法為子類的靜态方法;通過父類通路的靜态方法為父類的靜态方法,即使父類的真實類型是子類類型,調用的也是父類的靜态方法!

示例:

public class Test 
{
	public static void fun()
	{
		System.out.println("Test fun()");
	}
	
	public static void main(String args[])
	{
		Test t1 = new Test();
		t1.fun(); //Test fun()
		
		TestSon t2 = new TestSon();
		t2.fun(); //TestSon fun()
		
		t1 = t2;
		t1.fun(); //Test fun()
	}
}

class TestSon extends Test
{
	public static void fun()
	{
		System.out.println("TestSon fun()");	
	}
}
           

3.3 final修飾符的影響:不管是靜态方法還是執行個體方法,隻要被final修飾,都不能實作方法重寫,否則編譯報錯!

4.修飾符通路範圍表:

JavaSE學習筆記(9.Java中的修飾符)

5.修飾符定義順序原則:

在Java語言規範中,描述Class Modifiers(8.1.1)、Field Modifiers(8.3.1)、Method Modifiers(8.4.3)、Constructor Modifiers(8.8.3)

JavaSE學習筆記(9.Java中的修飾符)
JavaSE學習筆記(9.Java中的修飾符)
JavaSE學習筆記(9.Java中的修飾符)
JavaSE學習筆記(9.Java中的修飾符)

6.關鍵字補充說明:

6.1 assert:

Java的斷言功能,應該是從C/C++衍生過來的功能,在調試場景中使用,需要通過-ea開關進行打開關閉!

assert true; //程式正常運作

assert false:"Err Msg"; //程式停止并輸出Err Msg

6.2 instanceof (後面章節補充與isInstance()差別):

instanceof關鍵字是用來,指出一個對象是否為一個類的執行個體,是傳回true,不是傳回false

示例:result = object instanceof class

在編譯态:class可以是object的父類、自身類、子類,編譯都會成功!

在運作态:class是object的父類、自身類,結果傳回true;class是object的子類,結果傳回false!

7.檔案名、類名、main方法之間的關系:

1. 一個檔案内可以定義多個類,可以都是包通路權限,但最多隻能有一個public屬性,并且public屬性的類名必須和檔案名一緻!

2. main方法(方法名區分大小寫,必須是小寫),方法屬性必須是public static void屬性,參數必須是字元串數組(String args[]);所屬于的類可以是public通路權限也可以是包通路權限,而且任何類都可以定義main方法!

繼續閱讀