一、 final
根據(jù)上下文環(huán)境,Java的關(guān)鍵字final的含義存在細(xì)微的區(qū)別,但通常它指的是“這是無法改變的”。不想做改變可能處于兩種原因:設(shè)計(jì)或效率。由于這兩個(gè)原因相差很遠(yuǎn),所以final有可能被誤用。 --《Java編程思想》
- final類不能被繼承,沒有子類,final類中的方法默認(rèn)是final類型的;
- final方法不能被子類的方法覆蓋,但是可以被繼承,且不能修飾構(gòu)造方法;
- final成員變量表示常量,只能被賦值一次,賦值后不再改變;
- 注意:類中所有的private方法都隱式地指定為final的,因?yàn)楦割惖膒rivate方法是不能被子類的方法覆蓋的。
(1) final類
當(dāng)將某個(gè)類定義為final時(shí),表明該類不能不繼承,換句話說就是出于某種考慮,該類的功能設(shè)計(jì)不需要對類做任何改動(dòng),又或出于安全考慮,不希望他有子類。
(2) final方法
使用final修飾方法原因有兩個(gè):
- 把方法鎖定,防止任何繼承類修改它的含義;
- 出于設(shè)計(jì)考慮,確保在繼承中是方法行為保持不變,并且不被覆蓋。
(3) final變量(數(shù)據(jù))
用final修飾的成員變量表示常量,一旦賦值后無法改變;用final修飾的變量有靜態(tài)變量,實(shí)例變量和局部變量;
final空白:Java允許生成“空白final”,空白final是指被聲明為final但未給定初值的域。無論什么情況,編譯器都確保空白final在使用前必須被初始化。但是,final空白在final關(guān)鍵字final的使用上提供了更大的靈活性,為此,一個(gè)類中的final數(shù)據(jù)成員就可以實(shí)現(xiàn)依對象而有所不同,卻有保持其恒定不變的特征。如下代碼所示:
public class Test{
public final int i;
public Test(int n){
i = n;
}
public static void main(String[] args) {
Test t1 = new Test(1);
System.out.println(t1.i);
Test t2 = new Test(3);
System.out.println(t2.i);
}
}
// output
//1
//3
final參數(shù):當(dāng)函數(shù)參數(shù)為final類型時(shí),你可以讀取使用該參數(shù),但是無法改變方法中該參數(shù)的值。
public class Test{
public void fn(final int n){
//n++; 錯(cuò)誤,不能修改其值;
System.out.println(n);
}
public static void main(String[] args) {
new Test().fn(3);
}
}
//output
//3
二、static
static表示“全局”或者“靜態(tài)”的意思,用來修飾成員變量和成員方法,也可以形成靜態(tài)static代碼塊,但是Java語言中沒有全局變量的概念。
被static修飾的成員變量和成員方法獨(dú)立于該類的任何對象。也就是說,它不依賴類特定的實(shí)例,被類的所有實(shí)例共享。只要這個(gè)類被加載,Java虛擬機(jī)就能根據(jù)類名在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi)定找到他們。因此,static對象可以在它的任何對象創(chuàng)建之前訪問,無需引用任何對象。
用public修飾的static成員變量和成員方法本質(zhì)是全局變量和全局方法,當(dāng)聲明它類的對象時(shí),不生成static變量的副本,而是類的所有實(shí)例共享同一個(gè)static變量。
- static變量
按照是否靜態(tài)的對類成員變量進(jìn)行分類可分兩種:一種是被static修飾的變量,叫靜態(tài)變量或類變量;另一種是沒有被static修飾的變量,叫實(shí)例變量。兩者的區(qū)別是:
對于靜態(tài)變量在內(nèi)存中只有一個(gè)拷貝(節(jié)省內(nèi)存),JVM只為靜態(tài)分配一次內(nèi)存,在加載類的過程中完成靜態(tài)變量的內(nèi)存分配,可用類名直接訪問(方便),當(dāng)然也可以通過對象來訪問(但是這是不推薦的)。
對于實(shí)例變量,每創(chuàng)建一個(gè)實(shí)例,就會為實(shí)例變量分配一次內(nèi)存,實(shí)例變量可以在內(nèi)存中有多個(gè)拷貝,互不影響(靈活)。 - static方法
靜態(tài)方法可以直接通過類名調(diào)用,任何的實(shí)例也都可以調(diào)用,因此靜態(tài)方法中不能用this和super關(guān)鍵字,不能直接訪問所屬類的實(shí)例變量和實(shí)例方法(就是不帶static的成員變量和成員成員方法),只能訪問所屬類的靜態(tài)成員變量和成員方法。因?yàn)閷?shí)例成員與特定的對象關(guān)聯(lián)!
因?yàn)閟tatic方法獨(dú)立于任何實(shí)例,因此static方法必須被實(shí)現(xiàn),而不能是抽象的abstract。 - static代碼塊
static代碼塊也叫靜態(tài)代碼塊,是在類中獨(dú)立于類成員的static語句塊,可以有多個(gè),位置可以隨便放,它不在任何的方法體內(nèi),JVM加載類時(shí)會執(zhí)行這些靜態(tài)的代碼塊,如果static代碼塊有多個(gè),JVM將按照它們在類中出現(xiàn)的先后順序依次執(zhí)行它們,每個(gè)代碼塊只會被執(zhí)行一次。
public class Test {
private static int a;
private int b;
static {
Test.a = 1;
System.out.println(a);
Test t = new Test();
t.fn();
t.b = 100;
System.out.println(t.b);
}
static {
Test.a = 3;
System.out.println(a);
}
public static void main(String[] args) {
// TODO 自動(dòng)生成方法存根
System.out.println("ABC123");
}
static {
Test.a = 5;
System.out.println(a);
}
public void fn() {
System.out.println("fn()");
}
}
//output
//1
//fn()
//100
//3
//5
//ABC123
注意:幾次debug測試中main方法都是在最后執(zhí)行的
static 和 final
static final用來修飾成員變量和成員方法,可簡單理解為“全局常量”!
對于變量,表示一旦給值就不可修改,并且通過類名可以訪問。對于方法,表示不可覆蓋,并且可以通過類名直接訪問。
特別要注意一個(gè)問題:
對于被static和final修飾過的實(shí)例常量,實(shí)例本身不能再改變了,但對于一些容器類型(比如,ArrayList、HashMap)的實(shí)例變量,不可以改變?nèi)萜髯兞勘旧恚梢孕薷娜萜髦写娣诺膶ο螅@一點(diǎn)在編程中用到很多。
三、this
1.表示類中的成員變量
public class Test{
String s = "Hello";
public Test(String s) {
System.out.println("s = " + s);
System.out.println("1 --> this.s = " + this.s);
this.s = s;//把參數(shù)值賦給成員變量,成員變量的值改變
System.out.println("2 --> this.s = " + this.s);
}
public static void main(String[] args) {
Test t = new Test("HelloWorld!");
System.out.println("s = " + t.s);//驗(yàn)證成員變量值的改變
}
}
//output
//s = HelloWorld!
//1 --> this.s = Hello
//2 --> this.s = HelloWorld!
//s = HelloWorld!
2.將自己作為參數(shù)
當(dāng)要將自己作為參數(shù)進(jìn)行傳遞時(shí),可以使用this。
class TestA {
public TestA() {
new TestB(this).print();// 將A對象自己傳入TestB構(gòu)造方法中,并調(diào)用B的方法
}
public void print() {
System.out.println("TestAA from A!");
}
}
class TestB {
TestA a;
public TestB(TestA a) {
this.a = a;
}
public void print() {
a.print();//調(diào)用A的方法
System.out.println("TestAB from B!");
}
}
public class Test {
public static void main(String[] args) {
TestA aaa = new TestA();
aaa.print();
TestB bbb = new TestB(aaa);
bbb.print();
}
}
//output
//TestAA from A!
//TestAB from B!
//TestAA from A!
//TestAA from A!
//TestAB from B!
3.代表匿名類或內(nèi)部類本身
public class Test {
int i = 1;
public Test() {
Thread thread = new Thread() {//此處Thread是一個(gè)匿名內(nèi)部類
public void run() {
for (int j=0;j<20;j++) {
Test.this.run();//使用Test.this調(diào)用外部類的方法
try {
sleep(1000);
} catch (InterruptedException ie) {
}
}
}
}; // 注意這里有分號
thread.start();
}
public void run() {
System.out.println("i = " + i);
i++;
}
public static void main(String[] args) throws Exception {
new Test();
}
}
4.代表同一個(gè)類中的別的構(gòu)造方法
public class Test {
private int a;
private String b;
public Test(int a){
this.a = a;
System.out.println(a);
}
public Test(int a, String b){
this(a);
this.b = b;
System.out.println(b);
}
public static void main(String[] args) throws Exception {
new Test(1,"HelloWorld");
}
}
//output
//1
//HelloWorld
注意:
1.在構(gòu)造調(diào)用另一個(gè)構(gòu)造函數(shù),調(diào)用動(dòng)作必須置于最起始的位置。
2.不能在構(gòu)造函數(shù)以外的任何函數(shù)內(nèi)調(diào)用構(gòu)造函數(shù)。
3.在一個(gè)構(gòu)造函數(shù)內(nèi)只能調(diào)用一個(gè)構(gòu)造函數(shù)。
5.傳遞多個(gè)參數(shù)
public class Test {
int a;
int b;
static void show(Test test) {//實(shí)例化對象
System.out.println(test.a + " " + test.b);
}
void fn() {
show(this);
}
public static void main(String[] args) {
Test test = new Test();
test.a = 9;
test.b = 10;
test.fn();
}
}
//output
//9 10