1齐媒、final關(guān)鍵字作用
final可以修飾類蒲每、方法、變量喻括。那么分別是什么作用呢邀杏?
(1)修飾類:表示類不可被繼承
(2)修飾方法:表示方法不可被覆蓋
(3)修飾變量:表示變量一旦被賦值就不可以更改它的值。java中規(guī)定final修飾成員變量必須顯示指定變量的值唬血。
2望蜡、final關(guān)鍵字修飾類
final關(guān)鍵字修飾類表示這個(gè)類是不可被繼承的.
3、final關(guān)鍵字修飾方法
final修飾的方法不能被重寫,但是可以重載拷恨。
下面給出了一個(gè)代碼例子脖律。
主要注意的是:父類中private的方法,在子類中不能訪問該方法腕侄,但是子類與父類private方法相同的方法名小泉、形參列表和返回值的方法芦疏,不屬于方法重寫,只是定義了一個(gè)新的方法微姊。
class ClassFinal3{
private void testClassFinalMethod(){};
}
// 實(shí)現(xiàn)final修飾的接口
class InnerClass4 extends ClassFinal3 {
void testClassFinalMethod(){};
}
使用final方法的原因有兩個(gè):
- 第一個(gè)原因是把方法鎖定酸茴,以防任何繼承類修改它的含義;
- 第二個(gè)原因是效率柒桑。在早期的Java實(shí)現(xiàn)版本中弊决,會將final方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過于龐大魁淳,可能看不到內(nèi)嵌調(diào)用帶來的任何性能提升(現(xiàn)在的Java版本已經(jīng)不需要使用final方法進(jìn)行這些優(yōu)化了)飘诗。
類中所有的private方法都隱式地指定為final。
4界逛、final關(guān)鍵字修飾變量
(1)修飾成員變量
- 如果final修飾的是類變量昆稿,只能在靜態(tài)初始化塊中指定初始值或者聲明該類變量時(shí)指定初始值。
- 如果final修飾的是成員變量息拜,可以在非靜態(tài)初始化塊溉潭、聲明該變量或者構(gòu)造器中執(zhí)行初始值。
(2)修飾局部變量
系統(tǒng)不會為局部變量進(jìn)行初始化少欺,局部變量必須顯示初始化喳瓣。因此使用final修飾局部變量時(shí),即可以在定義時(shí)指定默認(rèn)值(后面的代碼不能對變量再賦值)赞别,也可以不指定默認(rèn)值畏陕,而在后面的代碼中對final變量賦初值(僅一次)。
實(shí)例:
package com.jvm.study;
public class FinalVar {
final static int a = 0;//再聲明的時(shí)候就需要賦值
public static void main(String[] args) {
final int localA; //局部變量只聲明沒有初始化仿滔,不會報(bào)錯(cuò),與final無關(guān)惠毁。
localA = 0;//在使用之前一定要賦值
localA = 1; // 但是不允許第二次賦值 Variable 'localA' might already have been assigned to
a = 1;// Cannot assign a value to final variable 'a'
}
}
(3)修飾基本類型數(shù)據(jù)和引用類型數(shù)據(jù)
- 如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改崎页;
- 如果是引用類型的變量鞠绰,則在對其初始化之后便不能再讓其指向另一個(gè)對象。但是引用的值是可變的飒焦。
使用示例
package com.jvm.study;
public class FinalReferenceTest {
public static void main() {
final int[] iArr = {1, 2, 3, 4};
iArr[2] = -3;//合法
iArr = null;//非法蜈膨,對iArr不能重新賦值 Cannot assign a value to final variable 'iArr'
final Person p = new Person(25);
p.setAge(24);//合法
p.setAge(12);//合法
p = null;//非法 Cannot assign a value to final variable 'p'
}
static class Person {
private int Age;
Person(int Age) {
this.Age = Age;
}
public int getAge() {
return Age;
}
public void setAge(int age) {
Age = age;
}
}
}
5、與Static關(guān)鍵字
static簡介
static是靜態(tài)修飾符牺荠,一般修飾成員翁巍。
被static修飾的成員屬于類,不屬于單個(gè)這個(gè)類的某個(gè)對象志电。static修飾的成員被多個(gè)對象共享曙咽。static修飾的成員屬于類蛔趴,但是會影響每一個(gè)對象挑辆。被static修飾的成員又叫類成員例朱,不叫對象的成員。
注意:static不能修飾類 構(gòu)造方法 局部變量鱼蝉。
成員變量使用
使用不同類中的成員變量有以下幾種方式:
- (1) 創(chuàng)建該類對象洒嗤,使用對象調(diào)用
- (2) 繼承,使用super調(diào)用
- (3) 使用類名直接調(diào)用魁亦,調(diào)用格式:類名.靜態(tài)成員變量名
stati修飾成員變量的注意事項(xiàng)
- (1)靜態(tài)方法可以直接訪問類變量和靜態(tài)方法渔隶。
- (2) 靜態(tài)方法不能直接訪問非靜態(tài)成員變量或成員方法。非靜態(tài)成員方法可以直接訪問類變量或靜態(tài)方法洁奈。
- (3) 靜態(tài)方法中间唉,不能使用this關(guān)鍵字。
static和final聯(lián)合使用
- static和final可以修飾成員變量和成員方法利术,對于變量呈野,可理解為“全局變量”,一旦賦值印叁,不能被修改被冒,可通過類名訪問;對于方法轮蜕,不能被子類覆蓋昨悼,可通過類名訪問。
- private 方法默認(rèn)均為 final 方法.
- final 常常和 static, public 配合來修飾一個(gè)實(shí)例變量跃洛,表示為一個(gè)全類公有的公開靜態(tài)常量率触。
6、不變模式
關(guān)于 final 的設(shè)計(jì)模式: 不變模式
1税课、不變模式: 一個(gè)對象一旦產(chǎn)生就不可能再修改(String 就是典型的不變模式)闲延;通過不變模式可以做到對象共享;
-
2韩玩、池化思想: 用一個(gè)存儲區(qū)域來存放一些公用資源以減少存儲空間的開銷垒玲。
有池的類型:boolean,byte,int,short,long,char,(池范圍在-127~128之間)(float,double 等小數(shù)沒有池)
例: 在String類中有個(gè)串池(在代碼區(qū))。
池: 堆里的一片獨(dú)立空間找颓。目的是拿空間換時(shí)間合愈,讓運(yùn)算效率更高。-
如果用Stirng str = "abc" 來創(chuàng)建一個(gè)對象時(shí)击狮,則系統(tǒng)會先在“串池”中尋找有沒有“abc”這個(gè)字符串;
如果有則直接將對象指向串池中對應(yīng)的地址佛析,如果沒有則在串池中創(chuàng)建一個(gè)“abc”字符串。所以:
String str1 = "abc"; String str2 = "abc"; Str1 == str2 //返回值是ture;他們的地址是一樣的彪蓬。 //也就是說str1和str2都指向了代碼空間中相同的一個(gè)地址寸莫,而這個(gè)地址空間保存就是是字符串"abc" //字符串是不可改變的類型,所以可以共享档冬。所以串池里不會有相同的兩個(gè)字符串膘茎。
-
如果用 String str = new String("abc") 則直接開辟一塊內(nèi)存放"abc"這個(gè)字符串桃纯。所以上面這語句,創(chuàng)建兩個(gè)"abc"披坏,一個(gè)在池态坦,一個(gè)是對象
String str = new String("abc") String str2 = new String("abc"); Str == str2 //返回值是false;他們的地址是不一樣的。
-
//即是說str和str2分別指向了堆空間中不同的兩個(gè)地址棒拂,而這兩個(gè)地址空間保存的都是字符串"abc"
```
7伞梯、final變量在內(nèi)部類中使用
package com.jvm.study;
public class Test {
public static void main(String[] args) {
}
//局部final變量b
public void test(final int b) {
int a = 10;//局部變量a
//匿名內(nèi)部類
new Thread(() -> {
System.out.println(a);//JDK1.7及其之前版本 報(bào)錯(cuò)
System.out.println(b);
// a = 1; // 不可修改 Variable used in lambda expression should be final or effectively final
// b = 1; // 不可修改 Cannot assign a value to final variable 'b'
}).start();
}
/**
* 上段代碼中,在JDK1.7及其之前版本帚屉,如果把變量a和b前面的任一個(gè)final去掉谜诫,這段代碼都編譯不過。
* 這段代碼會被編譯成兩個(gè)class文件:Test.class和Test1.class攻旦。
* 默認(rèn)情況下猜绣,編譯器會為匿名內(nèi)部類和局部內(nèi)部類起名為Outter1.class。
* 原因是為什么呢敬特?這是因?yàn)閠est()方法里面的參數(shù)a和b掰邢,在運(yùn)行時(shí),main線程快要結(jié)束伟阔,但是thread還沒有開始辣之。
* 因此需要有一種機(jī)制,在使得運(yùn)行thread線程時(shí)候能夠調(diào)用a和b的值皱炉,怎辦呢怀估?java采用了一種復(fù)制的機(jī)制,
* 也就說如果局部變量的值在編譯期間就可以確定合搅,則直接在匿名內(nèi)部里面創(chuàng)建一個(gè)拷貝多搀。
* 如果局部變量的值無法在編譯期間確定,則通過構(gòu)造器傳參的方式來對拷貝進(jìn)行初始化賦值灾部。
*/
}
匿名也會被當(dāng)作普通的類處理康铭,只不過編譯器生成它構(gòu)造方法的時(shí)候,除了將外部類的引用傳遞了過來赌髓,還將基本數(shù)據(jù)類型的變量復(fù)制了一份過來从藤,并把引用數(shù)據(jù)類型的變量引用也傳遞了過來。
因此锁蠕,基本數(shù)據(jù)類型的變量不能修改夷野,不然就會跟外部的變量產(chǎn)生不一致,這樣的話變量的傳遞也就變得毫無意義了荣倾。
JDK1.8之前局部內(nèi)部類和匿名內(nèi)部類訪問的局部變量必須由final修飾悯搔,JDK1.8開始,可以不加final修飾符舌仍,由JVM默認(rèn)添加妒貌。這個(gè)功能稱為:Effectively final 功能者娱,屬于Java的一種語法糖,final關(guān)鍵字語法并沒有發(fā)生變化苏揣。
8、總結(jié)
final關(guān)鍵字主要用在三個(gè)地方:變量推姻、方法平匈、類。
一句話概括:
final關(guān)鍵字修飾類,表示類不可被繼承;final關(guān)鍵字修飾方法,表示方法不可被覆蓋;final關(guān)鍵字修飾變量,表示變量一旦被賦值就不可以更改它的值藏古。java中規(guī)定final修飾成員變量必須顯示指定變量的值,并只能賦值一次增炭。