JAVA編程——static與final詳解

static

靜態成員

被static修飾的成語其實是一個類成員。
當這個類被虛擬機第一次加載的時候,就會爲該變量分配了內存空間。
當該類創建實例時,並不會生成對static變量的拷貝。而是多個該類的實例共享使用該變量。所有該類的對象都可以操作這塊存儲空間。如果用final修飾就另當別論了。

創建完成就需要進行初始化
1. 定義時直接初始化
2. 如果需要通過計算來初始化你的static變量,可以聲明一個static塊,Static 塊僅在該類被加載時執行一次,且在類被第一次裝載時。
【注意】static定義的變量的初始化會優先於任何其它非static變量,不論其出現的順序如何。(代碼1)
在涉及到繼承的時候,會先初始化父類的static變量,然後是子類的,依次類推。(自己驗證)

注意:
1. 可以使用”類名.變量名“直接使用,並且被該類所有實例化對象共享
2. 可以被類中所有方法使用(static與非static)
3. 該類中某一個對象修改了變量的值,其他所有該類對象中的對應值都會隨之改變
4. 定義時初始化,或者通過靜態代碼塊初始化

靜態方法

被static修飾的方法我們稱之爲類方法。可以死通過類直接調用該方法,而沒必要創建該類的實例後調用該方法。
1. 可以使用”類名.方法名“直接使用
2. 只能調用其他Static方法
3. 只能使用static成員變量
4. 不能以任何形式引用this和super
用途:靜態方法常常爲應用程序中的其它類提供一些實用工具,在Java的類庫中大量的靜態方法正是出於此目的而定義的。Arrays和Collections


靜態類
通常一個普通類不允許聲明爲靜態的,只有一個內部類纔可以。這時這個聲明爲靜態的內部類可以直接作爲一個普通類來使用,而不需實例一個外部類。(代碼2)

補充:

static表示“全局”或者“靜態”的意思,用來修飾成員變量和成員方法,也可以形成靜態static代碼塊,但是Java語言中沒有全局變量的概念。 


被static修飾的成員變量和成員方法獨立於該類的任何對象。也就是說,它不依賴類特定的實例,被類的所有實例共享。只要這個類被加載,Java虛擬機就能根據類名在運行時數據區的方法區內定找到他們。因此,static對象可以在它的任何對象創建之前訪問,無需引用任何對象。 


用public修飾的static成員變量和成員方法本質是全局變量和全局方法,當聲明它類的對象時,不生成static變量的副本,而是類的所有實例共享同一個static變量。 


static 變量前可以有private修飾,表示這個變量可以在類的靜態代碼塊中,或者類的其他靜態成員方法中使用(當然也可以在非靜態成員方法中使用--廢話),但是不能在其他類中通過類名來直接引用,這一點很重要。實際上你需要搞明白,private是訪問權限限定,static表示不要實例化就可以使用,這樣就容易理解多了。static前面加上其它訪問權限關鍵字的效果也以此類推。 


static修飾的成員變量和成員方法習慣上稱爲靜態變量和靜態方法,可以直接通過類名來訪問,訪問語法爲: 
類名.靜態方法名(參數列表...)
類名.靜態變量名 


用static修飾的代碼塊表示靜態代碼塊,當Java虛擬機(JVM)加載類時,就會執行該代碼塊(用處非常大,呵呵)。 


static變量 
按照是否靜態的對類成員變量進行分類可分兩種:一種是被static修飾的變量,叫靜態變量或類變量;另一種是沒有被static修飾的變量,叫實例變量。兩者的區別是: 
對於靜態變量在內存中只有一個拷貝(節省內存),JVM只爲靜態分配一次內存,在加載類的過程中完成靜態變量的內存分配,可用類名直接訪問(方便),當然也可以通過對象來訪問(但是這是不推薦的)。 
對於實例變量,沒創建一個實例,就會爲實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響(靈活)。 


static方法 
靜態方法可以直接通過類名調用,任何的實例也都可以調用,因此靜態方法中不能用this和super關鍵字,不能直接訪問所屬類的實例變量和實例方法 (就是不帶static的成員變量和成員成員方法


final


final特點:
1. 用final修飾的變量表示常量,只能被賦一次值,不能修改。

final修飾的成員變量沒有默認初始化值,需要顯式初始化
final修飾的基本類型變量:值不能被修改
final修飾的引用類型變量(對象):對象地址不能被修改,對象內部的成員可以被修改
被定義爲final的對象引用只能指向唯一一個對象,不可以將它再指向其他對象,但是一個對象內部的值卻是可以改變的。


被final修飾的變量是一個常量,必須被賦值後才能使用。可以在定義時賦值,也可在構造方法中賦值。(只要在構造方法結束前給賦值就OK。)


2. 用final修飾的方法不能被子類的方法覆蓋;

3. 用final修飾的類不能被繼承,沒有子類;
 final類不能被繼承,因此final類的成員方法沒有機會被覆蓋,默認都是final的。
 但是final類中的成員變量可以被定義爲final或非final形式。
 在設計類時候,如果這個類不需要有子類,類的實現細節不允許改變,那麼就設計爲final類。
4. final不能用來修飾構造方法。


示例:


3.
public class Something {
  public int addOne(final int x) {
      return ++x;
  }
}


4.
public class Something {
  public static void main(String[] args) {
      Other o = new Other();
      new Something().addOne(o);
  }
  public void addOne(final Other o) {  //o= 0x1234;
      o.i++;
  }
}


static和final
static final用來修飾成員變量和成員方法,可簡單理解爲“全局量”! 
對於變量,表示一旦給值就不可修改,並且通過類名可以訪問。 
對於方法,表示不可覆蓋,並且可以通過類名直接訪問。






抽象類與接口

抽象類:
含有abstract修飾符的class即爲抽象類,abstract 類不能創建的實例對象。含有abstract方法的類必須定義爲abstract class,abstract class類中的方法不必是抽象的。abstract class類中定義抽象方法必須在具體(Concrete)子類中實現,所以,不能有抽象構造方法或抽象靜態方法。如果的子類沒有實現抽象父類中的所有抽象方法,那麼子類也必須定義爲abstract類型。
接口:
可以說成是抽象類的一種特例,接口中的所有方法都必須是抽象的。接口中的方法定義默認爲public abstract類型,接口中的成員變量類型默認爲public static final。

下面比較一下兩者的語法區別:
1. 抽象類可以有構造方法,接口中不能有構造方法。
2. 抽象類中可以有普通成員變量,接口中沒有普通成員變量
3. 抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。
4. 抽象類中的抽象方法的訪問類型可以是public,protected,但接口中的抽象方法只能是public類型的,並且默認即爲public abstract類型。
5. 抽象類中可以包含靜態方法,接口中不能包含靜態方法
6. 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是public static final類型,並且默認即爲public static final類型。
7. 一個類可以實現多個接口,但只能繼承一個抽象類。




接口和抽象類的概念不一樣(通俗的講)。

接口是對動作的抽象,抽象類是對根源的抽象。


抽象類表示的是,這個對象是什麼。接口表示的是,這個對象能做什麼。比如,男人,女人,這兩個類(如果是類的話……),他們的抽象類是人。說明,他們都是人。鐵(iron)門、玻璃門這兩個類的抽象類是門,說明他們都是門。

人可以吃東西,狗也可以吃東西,你可以把“吃東西”定義成一個接口,然後讓這些類去實現它.


所以,Java中一個類只能繼承一個類(抽象類)(正如男人不可能同時是人和門),但是可以實現多個接口(吃飯接口、走路接口)。

當你關注一個事物的本質的時候,用抽象類;當你關注一個操作的時候,用接口。
 
接口可以實現也可以繼承,抽象類不行
抽象類的功能要遠超過接口,但是,定義抽象類的代價高。因爲高級語言來說(從實際設計上來說也是)每個類只能繼承一個類。在這個類中,你必須繼承或編寫出其所有子類的
所有共性。雖然接口在功能上會弱化許多,但是它只是針對一個動作的描述。而且你可以在一個類中同時實現多個接口。在設計階段會降低難度的。




代碼1:
<span style="font-family:Microsoft YaHei;font-size:14px;">package cn.itcast.employment.staticdemo;


class Person {
	//年齡
	public static int age = 0;
	
	//出生
	Person(){}
	
	//克隆人
	Person(int age){
		this.age = age;
	}
	
	//過了一年
	public void grow(){
		age++;
	}
}


public class staticDemo {
	
	Person p = new Person(10);
	
	static Person p1,p2;
	
	static{
		System.out.println("p1.age =" + p1.age + ",p2.age =" + p2.age);
		p1 = new Person(20);
		System.out.println("p1.age =" + p1.age + ",p2.age =" + p2.age);
		p2 = new Person(30);
		System.out.println("p1.age =" + p1.age + ",p2.age =" + p2.age);
	}
	
	public static void main(String[] args) {
		
		staticDemo sd = new staticDemo();
		
		System.out.println("p.age =" + sd.p.age);
		System.out.println("p1.age =" +p1.age + ",p2.age =" + p2.age);
		p1.grow();
		System.out.println("p1.age =" +p1.age + ",p2.age =" + p2.age);
		System.out.println(sd.p.age);
	}
}
</span>





代碼2:
public class StaticCls {
		public static void main(String[] args) {
			OuterCls.InnerCls oi = new OuterCls.InnerCls();
		}
	}


	class OuterCls {
		public static class InnerCls {
			InnerCls() {
				System.out.println("InnerCls");
			}
		}
	}




在JAVA中如何完全跳出當前的多重嵌套循環?


代碼:
方式一:可以在外面的循環語句前定義一個標號,然後在裏層循環體的代碼中使用帶有標號的break 語句,即可跳出外層循環。
<span style="font-family:Microsoft YaHei;font-size:14px;">	ok:for(int i=0;i<arr.length ;i++)
	{
		for(int j=0;j<arr[i].length;j++)
		{
			
			if(arr[i][j]  == 5) 
			{
				break ok;
			}
			System.out.println(“i=” + i + “,j=” + j);
		}
	}  
</span>


方式二:讓外層的循環條件表達式的結果可以受到裏層循環體代碼的控制,例如,要在二維數組中查找到某個數字。
<span style="font-family:Microsoft YaHei;font-size:14px;">int arr[][] = {{1,2,3},{4,5,6,7},{9}};
boolean found = true;
for(int i=0;i<arr.length && found;i++)
	{
		for(int j=0;j<arr[i].length;j++)
		{
			
			if(arr[i][j]  == 5) 
			{
				found = true;
				break;
			}
			System.out.println(“i=” + i + “,j=” + j);
		}
	} </span>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章