1. 程式人生 > >java修飾符public final static abstract transient

java修飾符public final static abstract transient

概念 日期 一個 strac 出錯 獲得 多線程 操作 單元

JAVA 修飾符public final static abstract transient
關鍵字: public final static abstract ...
1.public protected default private 組

位置 private 默認 protected public 同一個類 是 是 是 是 同一個包內的類 否 是 是 是 不同包內的子類 否 否 是 是 不同包並且不是子類 否 否 否 是
public 訪問權限最高,不論是不是同一個包或是否是子類 都可以訪問
protected 其次只有是不同包且不是子類的無法訪問外,其它均可
默認級別 次之,要求只能是同一個包中的類才能訪問
private 只能是同一個類才能訪問

這些修飾符可以修飾方法或者屬性,但是類只能用public 或者不寫.

Java代碼

1. package test;
2.
3. //訪問修飾符的使用
4. public class PublicClass{
5.
6. public String publicVariable = "publicVariable" ;
7. private String privateVar = "private var";
8. protected String protectedVar ="protected var";
9. String defaultVar="defaultVar";
10.
11. private void showPrivate(){
12. System.out.println("Nobody will access!");
13. }
14.
15. public void showPublic(){
16. System.out.println("showPublic method!");
17. }
18.
19. public void showProtected(){
20. System.out.println("Show protected method!");
21. }
22.
23. void showDefault(){
24. System.out.println("Show default method!");
25. }
26. }

package test;

//訪問修飾符的使用
public class PublicClass{

public String publicVariable = "publicVariable" ;
private String privateVar = "private var";
protected String protectedVar ="protected var";
String defaultVar="defaultVar";

private void showPrivate(){
System.out.println("Nobody will access!");
}

public void showPublic(){
System.out.println("showPublic method!");
}

public void showProtected(){
System.out.println("Show protected method!");
}

void showDefault(){
System.out.println("Show default method!");
}
}



Java代碼

1. package test;
2.
3. //import test.PublicClass;
4. class Test{
5. private String var =" private variable in class-Test!";
6.
7. public static void main(String args[]){
8. Test t = new Test();
9. PublicClass pClass = new PublicClass();
10. //另外一個類中的共有屬性和方法是可以被外界所訪問的
11. System.out.println("可以訪問到的資源屬性:"+pClass.publicVariable);//可訪問
12. pClass.showPublic(); // 可訪問
13. /*
14. *以下兩條編譯錯誤,在另外一個類中的私有方法是訪問不到的
15. **/
16. //System.out.println("可以訪問到的資源屬性:"+pClass.privateVariable ); //不能訪問
17. // pClass.showPrivate(); //不能訪問
18. //私有變量自己可以訪問
19. System.out.println("私有變量自己可以訪問"+t.var);
20. //protected 成員可以被該類的成員和子類的成員訪問。
21. // 還可以被同一個包中內的其他類成員訪問
22. System.out.println("可以訪問到的資源屬性:"+pClass.protectedVar);//可訪問
23. pClass.showProtected();//可訪問
24. System.out.println("可以訪問到的資源屬性:"+pClass.defaultVar);//可訪問
25. pClass.showDefault();//可訪問
26. }
27. }

package test;

//import test.PublicClass;
class Test{
private String var =" private variable in class-Test!";

public static void main(String args[]){
Test t = new Test();
PublicClass pClass = new PublicClass();
//另外一個類中的共有屬性和方法是可以被外界所訪問的
System.out.println("可以訪問到的資源屬性:"+pClass.publicVariable);//可訪問
pClass.showPublic(); // 可訪問
/*
*以下兩條編譯錯誤,在另外一個類中的私有方法是訪問不到的
**/
//System.out.println("可以訪問到的資源屬性:"+pClass.privateVariable ); //不能訪問
// pClass.showPrivate(); //不能訪問
//私有變量自己可以訪問
System.out.println("私有變量自己可以訪問"+t.var);
//protected 成員可以被該類的成員和子類的成員訪問。
// 還可以被同一個包中內的其他類成員訪問
System.out.println("可以訪問到的資源屬性:"+pClass.protectedVar);//可訪問
pClass.showProtected();//可訪問
System.out.println("可以訪問到的資源屬性:"+pClass.defaultVar);//可訪問
pClass.showDefault();//可訪問
}
}



2. final 修飾符
final 具有 不可更改的意思,它可以修飾非抽象類,非抽象成員方法和變量。
用 final 修飾的類不能被繼承,沒有子類 如 String
用 final 修飾的方法不能被子類的方法覆蓋
用 final 修飾的變量表示常量,只能被賦值一次
用 final 不能修飾構造方法,因為方法覆蓋這一概念僅適用於類的成員方法,而不適用於類的構造方法,父類的構造方法和子類的構造方法之間不存在覆蓋關系,因此用 final 修飾構造方法是豪無意義的。

父類中用 private 修飾的方法不能被子類的方法覆蓋,因此 private 類型的方法默認是 final 類型的。

final 類
String 類 ,不讓繼承,封裝實現的細節。

final 方法
在某些情況下,出於安全的原因,父類不允許子類覆蓋某個方法,此時可以把這個方法聲明為 finnal 類型。java.lang.Object 類,getClass()為 final 類型,equals()不為 final 類型。

final 變量
用 final 修飾的變量表示取值不會改變的常量。
final 修飾符可以修飾靜態變量,實例變量和局部變量,分別表示靜態常量,實例常量和局部常量。

例如 出生日期,年齡的限制等。
final 變量都必須顯示初始化,否則會導致編譯錯誤。
final 變量只能被賦值一次。

在程序中使用 final 修飾符來定義常量的作用
提高程序的安全性,禁止非法修改取值固定並且不允許修改的數據
提高程序代碼的可維護性。


3.transient 關鍵字
首先是JAVA的序列化,簡單來說就是將某一個類存儲以文件形式存儲在物理空間,下次再從本地還原的時候,還可以將它轉換回來,這種形式便利了網絡上的一些操作。

序列化只能保存對象的非靜態成員交量,不能保存任何的成員方法和靜態的成員變量,而且串行化保存的只是變量的值,對於變量的任何修飾符都不能保存。

以文件形式描述某些信息時,容易涉及到安全問題,因為數據位於Java運行環境之外,不在Java安全機制的控制之中。對於這些需要保密的字段,不應保存在永久介質中 ,或者不應簡單地不加處理地保存下來 ,為了保證安全性。應該在這些字段前加上transient關鍵字。它的意思是臨時的,即不會隨類一起序列化到本地,所以當還原後,這個關鍵字定義的變量也就不再存在。

如果TransTest 類的一個對象被序列化,i的內容不被保存,但j的將被保存。
Java代碼

1. class TransTest {
2. transient int i; //不需要保存
3. int j; //需要保存
4.

class TransTest {
transient int i; //不需要保存
int j; //需要保存
}



4. volatile關鍵字 不常用

Volatile修飾的成員變量在每次被線程訪問時,都強迫從共享內存中重讀該成員變量的值。而且,當成員變量發生變化時,強迫線程將變化值回寫到共享內存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。

Java語言規範中指出:為了獲得最佳速度,允許線程保存共享成員變量的私有拷貝,而且只當線程進入或者離開同步代碼塊時才與共享成員變量的原始值對比。

這樣當多個線程同時與某個對象交互時,就必須要註意到要讓線程及時的得到共享成員變量的變化。

而volatile關鍵字就是提示VM:對於這個成員變量不能保存它的私有拷貝,而應直接與共享成員變量交互。

使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當要訪問的變量已在synchronized代碼塊中,或者為常量時,不必使用。

由於使用volatile屏蔽掉了VM中必要的代碼優化,所以在效率上比較低,因此一定在必要時才使用此關鍵字。


5.Synchronize 關鍵字
先提出問題,如果開啟多線程同時操作同一實例變量,Thread-0線程從主內存中取出的值a 為 1,然後a++; Thread-1線程也從主內存中取出的值 a 進行 a+=2操作;Thread-0存入2到主內存中,Thread-1也存入,這樣就覆蓋了Thread-0存入的值.

原因是在JAVA 的內存模型中,是每一個進程都有一個主內存,每個線程都有自己的內存,線程從主內存取得數據,計算後再存回到主內存中.

解決這個問題就可以使用 synchronize關鍵字.
使用synchronized修飾此方法後,把下面的這幾個步驟當作一個原子操作:取數據,操作數據,存數據。原子操作是不能夠被打斷的,所以就保證了數據的一致性,這樣在同一時間有線程再執行,雖然在效率上比較有影響,但是能夠保證在同一時間只有一個線程能夠訪問到這一塊內存單元。

6.static 關鍵字
static 修飾符可以用來修飾類的成員變量,成員方法和代碼塊。
用 static 修飾的成員變量表示靜態變量,可以直接通過類來訪問。
用 static 修飾的成員方法表示靜態方法,可以直接通過類名來訪問。
用 static 修飾的程序代碼塊表示靜態代碼塊,當JAVA虛擬機加載類時,就會執行該代碼塊。
被 static 所修飾的成員變量和成員方法標明歸某個類所有,它不依賴於類的特定實例,被類的所有實例共享。只要這個類被加載,JAVA虛擬機就能根據類名在運行時數據區的方法區定位到它們。

static 變量
類的成員變量有兩種,一個是實例變量,沒有被 static 修飾,一種是被 static 修飾過的變量,叫類變量或者靜態變量。

靜態變量和實例變量的 區別:
靜態變量在內存中只有一個拷貝,運行時JAVA虛擬機只為靜態變量分配一次內存,在加載類的過程中完成靜態變量的內存分配。可以直接通過類名訪問靜態變量。
對於實例變量,每創建一個實例,就會為實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響。

static 方法
成員方法分為靜態方法和實例方法。用 static 修飾的方法叫做靜態方法,或者類方法。靜態方法和靜態變量一樣,不需要創建類的實例,可以直接通過類名來訪問。

因為靜態方法不需要通過它所屬的類的任何實例就會被調用,因此在靜態方法中不能使用 this 關鍵字,也不能直接訪問所屬類的實例變量和實例方法,但是可以直接訪問所屬類的靜態變量和靜態方法。
Java代碼

1.
2. class StaticTest{
3.
4. static int num =100;
5. int num1 = 20;
6.
7. static void staticMethod(){
8. System.out.println("StaticMethod!");
9. //System.out.println(this.num); //編譯錯誤,在static 方法內,不能使用this 關鍵字
10. //System.out.println(this.num1);//編譯錯誤,在static 方法內,不能使用this 關鍵字
11. // System.out.println(num1);//編譯錯誤,在static 方法內,不能直接訪問非 static 變量或者方法
12.
13. System.out.println(StaticTest.num);
14. }
15.
16. void LocalMethod(){
17. System.out.println("StaticMethod!");
18. }
19.
20.
21.
22. public static void main(String args[]){
23. StaticTest t = new StaticTest();
24.
25. //靜態變量被所有的實例共享
26. t.staticMethod();
27. System.out.println(t.num);
28. StaticTest.staticMethod();
29. System.out.println(StaticTest.num);
30. }
31. }
32.
33. // 總結:在靜態方法內不允許訪問非靜態變量 不能出現 this 和 supper


class StaticTest{

static int num =100;
int num1 = 20;

static void staticMethod(){
System.out.println("StaticMethod!");
//System.out.println(this.num); //編譯錯誤,在static 方法內,不能使用this 關鍵字
//System.out.println(this.num1);//編譯錯誤,在static 方法內,不能使用this 關鍵字
// System.out.println(num1);//編譯錯誤,在static 方法內,不能直接訪問非 static 變量或者方法

System.out.println(StaticTest.num);
}

void LocalMethod(){
System.out.println("StaticMethod!");
}



public static void main(String args[]){
StaticTest t = new StaticTest();

//靜態變量被所有的實例共享
t.staticMethod();
System.out.println(t.num);
StaticTest.staticMethod();
System.out.println(StaticTest.num);
}
}

// 總結:在靜態方法內不允許訪問非靜態變量 不能出現 this 和 supper


static 代碼塊
類中可以包含靜態代碼塊,它不存在於任何方法體中。在JAVA虛擬機加載類時會執行這些靜態代碼塊。如果類中包含多個靜態塊,那麽JAVA虛擬機將按照他們在類中出現的順序依次執行它,並且每個代碼塊只會被執行一次。

Java代碼

1. class StaticBlock{
2.
3. static int i =5;
4. int j;
5. static{
6. System.out.println("First :"+i++);
7. }
8.
9. static{
10. System.out.println("Sencond :" +i++);
11. }
12.
13. public static void main(String args[]){
14. StaticBlock s1 = new StaticBlock();
15. StaticBlock s2 = new StaticBlock();
16. System.out.println("Last :"+i);
17. }
18. }

class StaticBlock{

static int i =5;
int j;
static{
System.out.println("First :"+i++);
}

static{
System.out.println("Sencond :" +i++);
}

public static void main(String args[]){
StaticBlock s1 = new StaticBlock();
StaticBlock s2 = new StaticBlock();
System.out.println("Last :"+i);
}
}



靜態方法必須被實現
靜態方法用來表示某個類所特有的功能,這種功能的實現不依賴於類的具體實例,也不依賴於它的子類。既然如此,當前類必須為靜態方法提供實現,即一個靜態的方法不能被定義為抽象方法。

static 和 abstract 永遠不能放在一起用

如果一個方法是靜態的,它就必須自力更生,自己實現該方法。
如果一個方法是抽象的,那麽它就只表示類所具有的功能,但不會去實現它,在子類中才會去實現它。

作為程序入口的 main() 方法是靜態方法

因為把 main() 方法定義為靜態方法,可以使得JAVA虛擬機只要加載了 main 方法所屬的類,就能執行 main() 方法,而無須創建這個類的實例。

在 main() 方法中不能直接訪問實例變量和實例方法。

7.abstract 修飾符

類只能是(final+)默認或(final+)public或abstract修飾。其中final+abstract+class是不合法的,編譯出錯。
abstract 修飾符可以用來修飾類和成員方法
用 abstract 修飾的類表示抽象類,抽象類位於繼承樹的抽象層,抽象類不能被實例化,即不允許創建抽象類本身的實例。沒有用 abstract 修飾的類稱為具體類,具體類可以被實例化。
用 abstract 修飾的方法表示抽象方法,抽象方法沒有方法體。抽象方法用來描述系統具有什麽功能,但不提供具體的實現。沒有用 abstract 修飾的方法稱為具體方法,具體方法具有方法體。
abstract 語法規則:
抽象類可以沒有抽象方法,但包括了抽象方法的類必須被定義為抽象類。如果子類沒有實現父類中所有的抽象方法,那麽子類也必須被定義為抽象類。
以下一個父類
Java代碼


package test;

//抽象類

abstract class Shape{

//受保護的屬性
protected double length;
protected double width;

//構造方法
Shape(double num1,double num2){
this.length = num1;
this.width = num2;
}
//定義了一個抽象方法,方法體為空,只要有類繼承就必須實現這個抽象方法,否則子類也必須聲明為抽象類
abstract double area();
}

其中一個抽象方法 abstract double area();

現有一子類去實現這個父類,會出現什麽情況?

Java代碼

package test;

//子類繼承父類
class Square extends Shape{

Square(double num1,double num2){
super(num1,num2);
}
}


ERROR!!!

父類有一抽象方法 abstract double area();

子類必須去實現,否則本身也只能為抽象類。

所以,要麽:
Java代碼
package test;
//子類繼承父類
class Square extends Shape{
Square(double num1,double num2){
super(num1,num2);
}
//實現抽象方法
double area(){
System.out.println("正方形的面積為: ");
return length*width;
}
}
要麽:
Java代碼

package test;
//子類繼承父類
abstract class Square extends Shape{

Square(double num1,double num2){
super(num1,num2);
}
}

沒有抽象構造方法,也沒有抽象靜態方法。
abstract和static不能同時修飾方法,若是abstract方法則是普通方法,需要實現。
Java代碼

abstract class Base{
abstract Base() ;// 編譯出錯,構造方法不能是抽象的
static abstract void method() ;//編譯出錯, static 和 abstract 不能連用
static void method2(){}; //合法
}

抽象類中可以有非抽象的構造方法,創建子類的實例時可能會調用這些構造方法。抽象類不能被實例化,然而可以創建一個引用變量,其類型是一個抽象類,並讓它引用非抽象的子類的一個實例。
Java代碼
abstract class Base{}
class Sub extends Base{
public static void main(String args[]){
Base base1 = new Base (); //編譯出錯,不能創建抽象類B ase 的實例
Base base1 = new Sub(); // 合法,可以創建具體類Sub 的實例

}} 抽象類及抽象方法不能被 final 修飾符修飾。因為抽象類只允許創建子類,它的抽象方法才能被實現,並且只有它的具體子類才能被實例化,而用final 修飾的類不允許擁有子類,用 final 修飾的方法不允許被子類方法覆蓋,因此把abstract 修飾符與 final 修飾符連用,會導致自相矛盾。

java修飾符public final static abstract transient