Java中的關鍵字總結



Java中的關鍵字總結

1. final關鍵字

Java中的final關鍵字可以用來修飾類、方法和變量(包括實例變量和局部變量)

Tip:

  • 實例變量是類中方法外定義的變量,實例變量可以使用訪問修飾符public和private修飾,使用public修飾說明該變量對子類可見,使用private修飾則子類不可見,該變量只能在本類可見,實例變量具有默認值;

  • 局部變量是在方法中定義的變量,不能用訪問修飾符修飾,但是可以使用final關鍵字修飾(局部變量本省就是一種有限制的變量,只可以局部調用,因此沒有必要使用訪問修飾符修飾)

1.1 final關鍵字的基本用法

1.1.1 final修飾類

使用final修飾類則該類不能被繼承,同時類中的所有成員方法都會被隱式定義為final方法(只有在需要確保類中的所有方法都不被重寫時才使用final修飾類)。

final修飾類的成員變量是可以更改的

public final class FinalClass{

	int i = 1;
    
	void test(){
		System.out.println("FinalClass:test");
	}
    
	public static void main( String[] args ){
		FinalClass ficl = new FinalClass();
    
		System.out.println("ficl.i = " + ficl.i);
		ficl.i = 2;
		System.out.println("ficl.i = " + ficl.i);
	}
}

1.1.2 final修飾方法

使用final修飾方法可以將方法“鎖定”,以防止任何繼承類對方法的修改,也即使用final修飾方法,則子類無法重寫(但並不影響繼承和重載,即子類調用父類方法不受影響)。

1.1.3 final修飾變量

使用final關鍵字修飾變量是使用最多的情況

  • 使用final修飾變量的值不能做再次更改,即不能重新賦值

如果final修飾的變量是基本數據類型,則變量的值不可更改;
如果final修飾的變量是引用數據類型,則該變量不能再次指向其他引用(如重新指向新的對象或數組)但是該變量本身的內容可以再做修改(如數組本身的內容,或者對象的屬性的修改)

  • 無論final修飾實例變量還是局部變量,都必須在使用前顯式賦初值

Java中的實例變量系統會對其默認賦初值,但是局部變量必須先聲明后賦值再使用

在下面的例子中,沒有對src賦初值,如果程序正確,那么會在2步驟中給src賦值,但是如果2步驟中讀文件出現問題,那么在4步驟中使用src就會出錯,因此從程序的健壯性考慮,應對src賦初值,即0步驟

public void fun(){

	//BufferedImage src = null;//0. 聲明的同時賦值
	BufferedImage src;//1. 這里不用賦初值,也不會出錯
	try{
		src = ImageIO.read(new File("1.jpg"));//2.
	} catch (Exception e){
	//3. 如果出異常了就會進入這里,那么src可能無法被賦值
	}
	
	System.out.println(src.getHeight()); //4. src不一定有值,所以無法使用
}

雖然對於實例變量,系統會默認賦初值,但是Java仍然規定final修飾的實例變量必須顯式賦初值。實例變量顯式賦值的時機可以是在聲明時直接賦值,也可以先聲明,后在構造方法中賦值(對於含有多個構造方法,必須在每個構造方法中都顯示賦值)

  • 如果靜態變量同時被final修飾則可以將變量視為全局變量,即在整個類加載期間,其值不變。(static保證變量屬於整個類,在類加載時只對其分配一次內存;final保證變量的值不被改變)

1.2 final 關鍵字相關問題

1.2.1 final變量和普通變量的區別

final變量一旦被初始化賦值之后,就不能再被賦值了。


public class Test{
	public static void main(String[] args){
		String a = "hello2"; 
		final String b = "hello";
		String d = "hello";
		String c = b + 2; 
		String e = d + 2;
		System.out.println((a == c));//輸出true
		System.out.println((a == e));//輸出false
	}
}

當final變量是基本數據類型以及String類型時,如果在編譯期間能知道它的確切值,則編譯器會把它當做編譯期常量使用。也就是說在用到該final變量的地方,相當於直接訪問的這個常量,不需要在運行時確定。(類似於c語言中的宏替換)

上面的一段代碼中,由於變量b被final修飾,因此會被當做編譯器常量,所以在使用到b的地方會直接將變量b 替換為它的 值。而對於變量d的訪問卻需要在運行時通過鏈接來進行。

1.2.2 final和static

使用final修飾是用以保證變量不被改變,而使用static修飾成員變量,則成員變量在類中只保存一份副本。

在下列代碼中,i的兩次輸出都不一樣,而j的兩次輸出為同一值。

public class Test {
	public static void main(String[] args){
		MyClass myClass1 = new MyClass();
		MyClass myClass2 = new MyClass();
		System.out.println(myClass1.i);
		System.out.println(myClass1.j);
		System.out.println(myClass2.i);
		System.out.println(myClass2.j);
	 
	}
}

class MyClass{
	public final double i = Math.random();
	public static double j = Math.random();
}

2. staitc關鍵字

static關鍵字主要用來修飾成員變量和成員方法,在《Java編程思想》中對static關鍵字有如下闡述:

static方法就是沒有this的方法。在static方法內部不能調用非靜態方法,反過來是可以的。而且可以在沒有創建任何對象的前提下,僅僅通過類本身來調用static方法。這實際上正是static方法的主要用途。

簡言之,使用static的目的是為了在不創建對象的前提下來調用方法/變量。

2.1 static的基本用法

2.1.1 static方法

static方法一般稱作靜態方法,由於靜態方法不依賴於任何對象就可以進行訪問,因此對於靜態方法來說,是沒有this的,因為它不依附於任何對象,既然都沒有對象,就談不上this了。並且由於這個特性,在靜態方法中不能訪問類的非靜態成員變量和非靜態成員方法,因為非靜態成員方法/變量都是必須依賴具體的對象才能夠被調用。

但是要注意的是,雖然在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,但是在非靜態成員方法中是可以訪問靜態成員方法/變量的。

如果說想在不創建對象的情況下調用某個方法,就可以將這個方法設置為static。static修飾成員方法最大的作用,就是可以使用"類名.方法名"的方式調用方法,避免了new出對象的繁瑣和資源消耗。

我們最常見的static方法就是main方法。至於為什么main方法必須是static的,這是因為程序在執行main方法的時候沒有創建任何對象,因此只有通過類名來訪問。

2.1.2 static變量

static變量也稱作靜態變量,靜態變量和非靜態變量的區別是:靜態變量被所有的對象所共享,在內存中只有一個副本,它當且僅當在類初次加載時會被初始化。而非靜態變量是對象所擁有的,在創建對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。

static成員變量的初始化順序按照定義的順序進行初始化。

2.1.3 static代碼塊

static塊可以置於類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,並且只會執行一次。為什么說static塊可以用來優化程序性能,是因為它的特性:只會在類加載的時候執行一次。

所謂的代碼塊就是當我們初始化static修飾的成員時,可以將他們統一放在一個以static開始,用花括號包裹起來的塊狀語句中。

class Person{
	private Date birthDate;
	 
	public Person(Date birthDate){
		this.birthDate = birthDate;
	}
	 
	boolean isBornBoomer(){
		Date startDate = Date.valueOf("1946");
		Date endDate = Date.valueOf("1964");
		return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
	}
}

isBornBoomer是用來這個人是否是1946-1964年出生的,而每次isBornBoomer被調用的時候,都會生成startDate和birthDate兩個對象,造成了空間浪費,如果改成這樣效率會更好:

class Person{
	private Date birthDate;
	private static Date startDate,endDate;
	static{
		startDate = Date.valueOf("1946");
		endDate = Date.valueOf("1964");
	}
	 
	public Person(Date birthDate){
		this.birthDate = birthDate;
	}
	 
	boolean isBornBoomer(){
		return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
	}
}

將一些只需要進行一次的初始化操作都放在static代碼塊中進行

2.2 static 關鍵字相關問題

2.2.1 static關鍵字不影響訪問權限

使用static關鍵字修飾只是說明該成員變量屬於整個類的所有對象,但是並不影響該成員變量的訪問權限,如使用private static 修飾的成員變量只有在本類中可見,在其他類中不能通過“類名.變量名”調用。

2.2.2 static關鍵字和局部變量

在Java中不能使用static關鍵字修飾局部變量

2.2.3 能否使用this調用靜態成員變量

雖然對於靜態方法來說沒有this的說法而言,但是在非靜態方法中能夠通過this訪問靜態成員變量,這是由於靜態成員變量是被類的所有對象所共享的,那么也當然能被this所指向的當前對象調用。

public class Main{
	static int value = 33;
	 
	public static void main(String[] args) throws Exception{
		new Main().printValue();
	}
	 
	private void printValue(){
		int value = 3;
		System.out.println(this.value);//輸出33
	}
}

this代表當前對象,那么通過new Main()來調用printValue的話,當前對象就是通過new Main()生成的對象。而static變量是被對象所享有的,因此在printValue中的this.value的值毫無疑問是33。在printValue方法內部的value是局部變量,根本不可能與this關聯,所以輸出結果是33。

靜態成員變量雖然獨立於對象,但是不代表不可以通過對象去訪問,所有的靜態方法和靜態變量都可以通過對象訪問(只要訪問權限足夠)。


3. this關鍵字

this代表它所在函數所屬對象的引用。簡單說:哪個對象在調用this所在的函數,this就代表哪個對象。

this關鍵字主要有以下三個作用:

  • this調用本類中的屬性,也就是類中的成員變量;
  • this調用本類中的其他方法;
  • this調用本類中的其他構造方法,調用時要放在構造方法的首行。(this語句只能定義在構造函數的第一行,因為在初始化時須先執行)

3.1 this關鍵字的基本用法

3.1.1 引用成員變量

public class Person{ 
	String name; //定義成員變量name
	private void SetName(String name) { //定義一個參數(局部變量)name
	this.name=name; //將局部變量的值傳遞給成員變量
	}
}

如上面這段代碼中,Person類中有一個成員變量name,同時在SetName方法中有一個形式參數,名字也是name,然后在方法中將形式參數name的值傳遞給成員變量nam。

雖然我們可以看明白這個代碼的含義,但是作為Java編譯器它是怎么判斷的呢?到底是將形式參數name的值傳遞給成員變量name,還是反過來將成員變量name的值傳遞給形式參數name呢?也就是說,兩個變量名字如果相同的話,那么Java如何判斷使用哪個變量?

此時this這個關鍵字就起到作用了。this這個關鍵字其代表的就是對象中的成員變量或者方法。也就是說,如果在某個變量前面加上一個this關鍵字,其指的就是這個對象的成員變量或者方法,而不是指成員方法的形式參數或者局部變量。

因此在上述代碼中,this.name代表的就是對象中的成員變量,又叫做對象的屬性,而后面的name則是方法的形式參數,代碼this.name=name就是將形式參數的值傳遞給this指向對象的成員變量。

一看到這個this關鍵字就知道現在引用的變量是成員變量或者成員方法,而不是局部變量。這無形中就提高了代碼的閱讀性。

3.1.2 調用類的構造器方法

public class Person { 
	public Person(){ //無參構造器方法
	this(“Hello!”);
	}
	public Person(String name){ //定義一個帶形式參數的構造方法
	}
}

在上述代碼中,定義了兩個構造方法,一個帶參數,另一個沒有帶參數。在第一個沒有帶參數的構造方法中,使用了this(“Hello!”)這句代碼,這句代碼表示什么含義呢?在構造方法中使this關鍵字表示調用類中的構造方法。

如果一個類中有多個構造方法,因為其名字都相同,跟類名一致,那么這個this到底是調用哪個構造方法呢?其實,這跟采用其他方法引用構造方法一樣,都是通過形式參數來調用構造方法的。

Tip:

語法限制:利用this關鍵字來調用構造方法,只有在無參數構造方法中第一句使用this調用有參數的構造方法。否則的話,翻譯的時候,就會有錯誤信息。這跟引用成員變量不同。如果引用成員變量的話,this關鍵字是沒有位置上的限制的。

3.1.3 返回對象的引用

this關鍵字除了可以引用變量或者成員方法之外,還有一個關鍵的作用就是返回對象的引用。

/**
     * 資源url
     */
public HttpConfig url(String url) {
	urls.set(url);
	//return this就是返回當前對象的引用(就是實際調用這個方法的實例化對象)
	return this;
}


調用:

HttpConfig  config = HttpConfig.custom();
config = config.url(url);

return this就是返回當前對象的引用(就是實際調用這個方法的實例化對象)

3.1.4 this關鍵字和super關鍵字

在JAVA類中使用super來引用父類的成分,用this來引用當前對象

如果一個類從另外一個類繼承,我們new這個子類的實例對象的時候,這個子類對象里面會有一個父類對象。怎么去引用里面的父類對象呢?使用super來引用,this指的是當前對象的引用,super是當前對象里面的父對象的引用


class FatherClass {
	public int value;
	public void f() {
		value=100;
		System.out.println("父類的value屬性值="+value);
	}
}


class ChildClass extends FatherClass {
	/**
	* 子類除了繼承父類所具有的valu屬性外,自己又獨立聲明了一個value屬性,
	*/
	public int value;
	
	/**
	* 在子類ChildClass里面重寫了從父類繼承下來的f()方法里面的實現,即重寫了f()方法的方體。
	*/
	public void f() {
		super.f();//使用super作為父類對象的引用對象來調用父類對象里面的f()方法
		value=200;//這個value是子類自己定義的那個value,不是從父類繼承下來的那個value
		
		System.out.println("子類的value屬性值="+value);
		System.out.println(value);//打印出來的是子類自定義的那個value的值,這個值是200
		
		/**
		* 打印出來的是父類里面的value值,由於子類在重寫從父類繼承下來的f()方法時,
		* 第一句話“super.f();”是讓父類對象的引用對象調用父類對象的f()方法,
		* 即相當於是這個父類對象自己調用f()方法去改變自己的value屬性的值,由0變了100。
		* 所以這里打印出來的value值是100。
		*/
		System.out.println(super.value);
	}
}


/**
 * 測試類
 *
 */
public class TestInherit {
	public static void main(String[] args) {
		ChildClass cc = new ChildClass();
		cc.f();
	}
}
  • 屬性的區別:this訪問本類中的屬性,如果本類沒有此屬性則從父類中繼續查找。super訪問父類中的屬性。
  • 方法的區別:this訪問本類中的方法,如果本類沒有此方法則從父類中繼續查找。super訪問父類中的方法。
  • 構造的區別:this調用本類構造,必須放在構造方法的首行。super調用父類構造,必須放在子類構造方法首行。
  • 其他區別:this表示當前對象。super不能表示當前對象

Tips:

  • 在對擁有父類的子類進行初始化時,父類的構造方法也會執行,且優先於子類的構造函數執行;因為每一個子類的構造函數中的第一行都有一條默認的隱式語句super();
    (如果子類的構造方法中沒有手動調用父類的構造方法,則會默認調用父類的無參構造方法)
  • this() 和super()都只能寫在構造函數的第一行;
  • this() 和super() 不能存在於同一個構造函數中。第一,this()和super()都必須寫在構造函數的第一行;第二,this()語句調用的是當前類的另一個構造函數而這個另一個構造函數中必然有一個父類的構造器,再使用super()又調用一次父類的構造器, 就相當於調用了兩次父類的構造器,編譯器不會通過;
  • this和super不能用於static修飾的變量,方法,代碼塊;因為this和super都是指的是對象/實例。

參考鏈接:

淺析Java中的final關鍵字

Java中的static關鍵字解析

Java中this關鍵字詳解

super關鍵字


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM