關鍵字static
static:靜態的,用於修飾類的成員;被static修飾的成員,在字節碼文件(.class文件)被類加載器(Classloader)從硬盤加載到內存中時,就被在內存中創建。沒有被static修飾的成員在使用關鍵字new創建對象後才被創建
被static修飾的成員,一個類只有一份,不屬於某個對象,而且會常駐內存;
例如:地球屬於全人類,而不屬於某一個人。
靜態屬性的調用:類名.屬性名;
靜態方法的調用:類名.方法名();
靜態塊語法格式:static{ //代碼 };class文件被加載的時候執行一次
在靜態方法或靜態塊中直接調用類的屬性,這個屬性也必須是靜態的
當靜態的屬性和靜態塊或靜態方法在一個類中時,可以直接使用屬性名來訪問屬性
實例:
/**
* 演示關鍵字static的使用
* @author 學霸聯盟 - 趙燦
*/
public class StaticDemo {
// 聲明一個靜態的屬性name,並賦值爲“張三”
static String name = "張三";
// 聲明一個非靜態的屬性age,並賦值爲1
int age = 18;
// 聲明一個靜態方法
static void staticMethod1(){
System.out.println("靜態方法staticMethod1");
/*
* 這裏可以直接使用靜態成員name和staticMethod2
* 但是想要使用非靜態成員age、method1和method2
* 就必須創建對象,再使用對象調用非靜態的成員
*/
staticMethod2();
System.out.println("靜態的屬性name:" + name);
}
// 聲明一個靜態方法
static void staticMethod2(){
//這裏可以直接調用靜態成員
System.out.println("靜態方法staticMethod2");
}
// 聲明一個非靜態方法
void method1(){
System.out.println("非靜態方法method1");
//這裏可以直接使用靜態成員和非靜態成員
method2();
// 普通屬性必須使用對象調用
System.out.println("非靜態的屬性age:" + age);
}
// 聲明一個非靜態方法
void method2(){
System.out.println("非靜態方法method2");
}
/*
* main方法是靜態方法
* 靜態方法中可以直接使用本類靜態成員,也可以通過類名調用靜態成員
* 但使用非靜態成員時,無論是本來還是其他類,都要先創建對象
* 再通過對象去調用非靜態的成員
*/
public static void main(String[] args) {
// 靜態的成員可以直接使用類名.成員的方式調用,無需創建對象再調用
StaticDemo.staticMethod1();
// 創建一個Person類的對象p
StaticDemo sd = new StaticDemo();
sd.method1();
}
}
運行結果:
靜態方法staticMethod1
靜態方法staticMethod2
靜態的屬性name:張三
非靜態方法method1
非靜態方法method2
非靜態的屬性age:18
實例:
/**
* 演示普通代碼塊和靜態代碼塊
* @author 學霸聯盟 - 趙燦
*/
public class CodeBlockDemo {
static int si = 1;
int i = 1;
//靜態塊:只會再該類的class文件被加載時執行一次
static{
//靜態塊中可以直接使用靜態成員,但不能直接使用非靜態成員
System.out.println("靜態塊被執行");
}
//非靜態代碼塊:創建一個對象,就會被執行一次
{
//非靜態塊中可以直接使用靜態成員,也可以直接使用非靜態成員
System.out.println("普通代碼塊被執行");
}
public static void main(String[] args) {
//在main方法開始之前,靜態塊就已經執行
System.out.println("----- main方法開始 -----");
//未創建當前類的對象之前,就執行了靜態塊
System.out.println("si = " + si);
//普通代碼塊,創建對象時被執行
System.out.println("----- 創建對象開始 -----");
/*
* 創建一個對象時
*/
CodeBlockDemo cbd1 = new CodeBlockDemo();
//輸出結果:cbd1.si = 1 , cbd1.i = 1
System.out.println("cbd1.si = " + cbd1.si + " , cbd1.i = " + cbd1.i);
//對靜態屬性si和非靜態屬性i都進行修改
cbd1.si = 10;
cbd1.i = 10;
System.out.println("----- 再次創建對象開始 -----");
CodeBlockDemo cbd2 = new CodeBlockDemo();
//輸出結果:cbd1.si = 10 , i = 10
System.out.println("cbd1.si = " + cbd1.si + " , i = " + cbd1.i);
//輸出結果:cbd2.si = 10 , i = 1
System.out.println("cbd2.si = " + cbd2.si + " , i = " + cbd2.i);
}
}
運行結果:
靜態塊被執行
----- main方法開始 -----
si = 1
----- 創建對象開始 -----
普通代碼塊被執行
cbd1.si = 1 , cbd1.i = 1
----- 再次創建對象開始 -----
普通代碼塊被執行
cbd1.si = 10 , i = 10
cbd2.si = 10 , i = 1
由結果可以看出,靜態的屬性si一個類只有一份,兩個對象cdb1和cdb2共同擁有這一份,任何一個對象對靜態的屬性進行修改,其他對象訪問時也會隨之改變。而非靜態的屬性i,則是每個對象各有一份,所以修改某一個對象的非靜態屬性,其他對象不會隨之改變關鍵字this
一個指向自身的引用(變量),他在哪個對象中,他的值就是哪個對象的地址。實例:
/**
* 演示關鍵字this的使用
* @author 學霸聯盟 - 趙燦
*/
public class ThisDemo {
// 聲明一個變量a並賦值爲123
public int a = 123;
/*
* 聲明一個變量b並賦值爲變量a的值,所以變量b的值也是123
* 創建一個對象執行一次
*/
public int b = this.a;
// 聲明一個沒有返回值,沒有參數的方法print
public void print() {
// 聲明一個局部變量a,局部變量和成員變量可以重名
int a = 456;
// 變量a前沒用關鍵字this,代表使用的是局部變量a;輸出的值是456
System.out.println(a);
// 變量a前使用了關鍵字this,代表使用的是成員變量a;輸出的值是123
System.out.println(this.a);
// 由於沒有局部變量和成員變量b重名,所以前面的this可以省略
System.out.println(b);
System.out.println("this的地址:" + this);
}
//靜態的main方法
public static void main(String[] args) {
// new語句執行完,其中的變量a和b都有了值是123
ThisDemo td1 = new ThisDemo();
// 給對象td1的屬性a賦值爲789
td1.a = 789;
// 調用對象td1的print方法,此時ThisDemo類中使用的this都和td1中存儲的地址相同
td1.print();
System.out.println("td1的地址:" + td1);
// 創建對象td2
ThisDemo td2 = new ThisDemo();
// 使用對象td2調用print方法,此時ThisDemo類中使用的this都和td2中存的地址相同
td2.print();
System.out.println("td2的地址:" + td2);
}
}
輸出結果:
456
789
123
this的地址:cls.keyword.ThisDemo@659e0bfd
td1的地址:cls.keyword.ThisDemo@659e0bfd
456
123
123
this的地址:cls.keyword.ThisDemo@2a139a55
td2的地址:cls.keyword.ThisDemo@2a139a55
小結:
1、不能用在static修飾的成員中,因爲this代表的是對象的引用2、如果在非靜態的方法或非靜態的代碼塊中,沒有局部變量和屬性(成員變量)重名,this可以省略;否則,必須使用 this.屬性的方式來訪問類的屬性
3、調用本類的其他構造方法:this( [參數列表] )
使用關鍵字this調用構造方法時,只能在構造方法中調用,而且調用時必須寫在構造方法中的第一行;構造方法不能自己調用自己,不能相互調用