前面的更新已經提到過Java變量的定義規則與命名規則,這裏對於變量進行更深入一步理解。
Java中根據變量的定義位置,可以分成兩大類,每個大類又可以細分,具體的細分如下:
上圖應該很好的表現了變量的分類的區分以及基本特性,成員變量指在類裏面定義的變量,裏面根據是不是以static修飾可以分爲類變量與實例變量,成員變量可以不賦值直接使用,因爲系統會自動添加一個默認值,這個默認值的規則和數組裏的數組項的默認值的規則是一樣的,byte short int long 是0,double float是0.0,char是'/U0000',boolean是false,裏面的實例變量與類變量之間的區別是調用的方式不一樣,以及生命週期不同;而在方法裏定義的局部變量包括形參、方法局部變量、代碼塊局部變量,他們裏面形參是不用賦值的,但是形參的值是由調用方法賦實參,再由系統進行賦值的,而其餘兩個都是要先賦值再使用的。
在瞭解了這些特性以後,用代碼看看實參與形參的定義與調用:
class Demo{
//類成員變量
static int var1;
//實例成員變量
String var2;
void fun(int x){//形參
int y;
//方法局部變量
int z = 15;
// System.out.println(y);//編譯報錯,錯誤信息:局部變量尚未初始化
System.out.println(z);
}
{
//代碼塊局部變量
int y;
int z = 15;
// System.out.println(y);//編譯報錯,錯誤信息:局部變量尚未初始化
System.out.println(z);
}
}
public class Test03 {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(Demo.var1);//調用類變量-->輸出0
System.out.println(demo.var2);//調用實例變量-->輸出null
demo.fun(151);//調用方法時,給形參傳值
// 注意:方法裏的局部變量是訪問不到的,只能在方法裏訪問
}
}
參數的分類還是很好理解的,下面就一個案例,分析一下 各種參數在內存裏的存放位置與時間,正是因爲這些存放的不同導致的這些變量的差異,先將案例的代碼粘到下面:
class Person{
public static int eyeName;//類變量
public String name;//實例變量
}
public class Test04 {
public static void main(String[] args) {
Person p1 = new Person();//創建第一個對象
Person p2 = new Person();//創建第二個對象
p1.name = "張三";
p2.name = "李四";
p1.eyeName = 2;
System.out.println(p1.name);//張三
System.out.println(p2.name);//李四
System.out.println(p1.eyeName);//2
System.out.println(p2.eyeName);//2
}
}
先分析一個代碼,類Person有兩個變量,一個類變量,一個實例變量,在Test04的方法中,我們創建兩個Person實例,分別給兩個實例的實例變量賦值,然後給p1的類變量賦值,然後,我們輸出這些變量,當然兩個實例變量輸出的都是我們賦的值,可是,類變量值設置了p1的,p2的沒有設置,但是兩個的都發生了改變,這是爲什麼?
原因我們也提到過,類變量是屬於類的,不屬於實例,所以儘管用實例去調用了,但是,這樣的寫法是特別的不推薦的,因爲會給人引起誤導,這一點《瘋狂Java講義》的作者也提到了,說用實例調用類變量,是Java中的一點缺陷,所以在編程的過程中要儘量的避免。下面,我們分別看看各個階段的內存加載狀態:
上面的圖很好的說明了成員變量的內存存放方式,下面我們分析一下局部變量的內存機制:
局部變量很特殊,不屬於類也不屬於對象,而是屬於方法或者代碼塊,所以存放在方法的棧內存中,先看一段代碼,
void fun(){
int i = 15;
String s = "hello";
}
很簡單的一個方法,我們看看圖示,
通過上圖應該很好的理解了。