在Java語言中,所有的變量在使用前必須聲明。聲明變量的基本格式如下:
格式說明:type為Java數據類型。identifier是變量名。可以使用逗號隔開來聲明多個同類型變量。以下列出了一些變量的聲明實例。注意有些包含了初始化過程:
int a, b, c; // 聲明三個int型整數:a、 b、c
int d = 3, e = 4, f = 5; // 聲明三個整數並賦予初值
byte z = 22; // 聲明並初始化 z
String s = "runoob"; // 聲明並初始化字符串 s
double pi = 3.14159; // 聲明了雙精度浮點型變量 pi
char x = 'x'; // 聲明變量 x 的值是字符 'x'。
Java語言支持的變量類型有:
- 類變量:獨立於方法之外的變量,用 static 修飾。
- 實例變量:獨立於方法之外的變量,不過沒有 static 修飾。
- 局部變量:類的方法中的變量。
咱們來看個實例:
public class Variable{
static int allClicks=0; // 類變量
String str="hello world"; // 實例變量
public void method(){
int i =0; // 局部變量
}
}
我們先來看下局部變量:
- 局部變量聲明在方法、構造方法或者語句塊中;
- 局部變量在方法、構造方法、或者語句塊被執行的時候創建,當它們執行完成后,變量將會被銷毀;
- 訪問修飾符不能用於局部變量;
- 局部變量只在聲明它的方法、構造方法或者語句塊中可見;
- 局部變量是在棧上分配的。
- 局部變量沒有默認值,所以局部變量被聲明后,必須經過初始化,才可以使用。
在以下實例中age是一個局部變量。定義在pupAge()方法中,它的作用域就限制在這個方法中:
package com.runoob.test;
public class Test{
public void pupAge(){
int age = 0;
age = age + 7;
System.out.println("小狗的年齡是: " + age);
}
public static void main(String args[]){
Test test = new Test();
test.pupAge();
}
}
以上實例編譯運行結果如下:
小狗的年齡是: 7
在下面的例子中 age 變量沒有初始化,所以在編譯時會出錯:
package com.runoob.test;
public class Test{
public void pupAge(){
int age;
age = age + 7;
System.out.println("小狗的年齡是 : " + age);
}
public static void main(String args[]){
Test test = new Test();
test.pupAge();
}
}
運行結果如下:
Test.java:4:variable number might not have been initialized age = age + 7; ^ 1 error
再來看下實例變量:
- 實例變量聲明在一個類中,但在方法、構造方法和語句塊之外;
- 當一個對象被實例化之后,每個實例變量的值就跟着確定;
- 實例變量在對象創建的時候創建,在對象被銷毀的時候銷毀;
- 實例變量的值應該至少被一個方法、構造方法或者語句塊引用,使得外部能夠通過這些方式獲取實例變量信息;
- 實例變量可以聲明在使用前或者使用后;
- 訪問修飾符可以修飾實例變量;
- 實例變量對於類中的方法、構造方法或者語句塊是可見的。一般情況下應該把實例變量設為私有。通過使用訪問修飾符可以使實例變量對子類可見;
- 實例變量具有默認值。數值型變量的默認值是0,布爾型變量的默認值是false,引用類型變量的默認值是null。變量的值可以在聲明時指定,也可以在構造方法中指定;
- 實例變量可以直接通過變量名訪問。但在靜態方法以及其他類中,就應該使用完全限定名:ObejectReference.VariableName。
public class Employee{
// 這個實例變量對子類可見
public String name;
// 私有變量,僅在該類可見
private double salary;
//在構造器中對name賦值
public Employee (String empName){
name = empName;
}
//設定salary的值
public void setSalary(double empSal){
salary = empSal;
}
// 打印信息
public void printEmp(){
System.out.println("名字 : " + name );
System.out.println("薪水 : " + salary);
}
public static void main(String args[]){
Employee empOne = new Employee("luyaran");
empOne.setSalary(1000);
empOne.printEmp();
}
}
上述實例運行結果如下:
$ javac Employee.java $ java Employee 名字 : luyaran 薪水 : 1000.0
再來看下類變量,也就是靜態變量:
- 類變量也稱為靜態變量,在類中以static關鍵字聲明,但必須在方法構造方法和語句塊之外。
- 無論一個類創建了多少個對象,類只擁有類變量的一份拷貝。
- 靜態變量除了被聲明為常量外很少使用。常量是指聲明為public/private,final和static類型的變量。常量初始化后不可改變。
- 靜態變量儲存在靜態存儲區。經常被聲明為常量,很少單獨使用static聲明變量。
- 靜態變量在程序開始時創建,在程序結束時銷毀。
- 與實例變量具有相似的可見性。但為了對類的使用者可見,大多數靜態變量聲明為public類型。
- 默認值和實例變量相似。數值型變量默認值是0,布爾型默認值是false,引用類型默認值是null。變量的值可以在聲明的時候指定,也可以在構造方法中指定。此外,靜態變量還可以在靜態語句塊中初始化。
- 靜態變量可以通過:ClassName.VariableName的方式訪問。
- 類變量被聲明為public static final類型時,類變量名稱一般建議使用大寫字母。如果靜態變量不是public和final類型,其命名方式與實例變量以及局部變量的命名方式一致。
import java.io.*;
public class Employee {
//salary是靜態的私有變量
private static double salary;
// DEPARTMENT是一個常量
public static final String DEPARTMENT = "開發人員";
public static void main(String args[]){
salary = 10000;
System.out.println(DEPARTMENT+"平均工資:"+salary);
}
}
運行結果如下:
開發人員平均工資:10000.0
在這里要注意下,如果其他類想要訪問該變量,可以這樣訪問:
Employee.DEPARTMENT。
我們再來看下靜態變量和實例變量之間的區別:
- 靜態變量屬於類,該類不生產對象,通過類名就可以調用靜態變量。
- 實例變量屬於該類的對象,必須產生該類對象,才能調用實例變量。
在程序運行時,它們的區別是:
- 實例變量屬於某個對象的屬性,必須創建了實例對象,其中的實例變量才會被分配空間,才能使用這個實例變量。
- 靜態變量不屬於某個實例對象,而是屬於類,所以也稱為類變量,只要程序加載了類的字節碼,不用創建任何實例對象,靜態變量就會被分配空間,靜態變量就可以被使用了。
總之呢,實例變量必須創建對象后才可以通過這個對象來使用,靜態變量則可以直接使用類名來引用。例如,對於下面的程序,無論創建多少個實例對象,永遠都只分配了一個 staticInt 變量,並且每創建一個實例對象,這個 staticInt 就會加 1;但是,每創建一個實例對象,就會分配一個 random,即可能分配多個 random ,並且每個 random 的值都只自加了1次。
public class StaticTest { private static int staticInt = 2; private int random = 2; public StaticTest() { staticInt++; random++; System.out.println("staticInt = "+staticInt+" random = "+random); } public static void main(String[] args) { StaticTest test = new StaticTest(); StaticTest test2 = new StaticTest(); } }
運行結果為:
staticInt = 3 random = 3 staticInt = 4 random = 3
靜態變量是用來聲明規則的,一旦固定都是用用來引用的,類似社會中的法律,規定好后你只能拿來說。但是也可以改的,通過重新的聲明法律就行。
java 實例變量在整個類內部是可訪問的,而不管實例變量聲明在類的哪個位置。比如在下面代碼中,盡管實例變量聲明在類的尾部,在之前方法中仍可訪問
import java.io.*; public class Employee{ public Employee (String empName){ name = empName; } public void setSalary(double empSal){ salary = empSal; } public void printEmp(){ System.out.println("name:" + name); System.out.println("salary:" + salary); } public static void main(String args[]){ Employee empOne = new Employee("RUNOOB"); empOne.setSalary(1000); empOne.printEmp(); System.out.println(empOne.salary); } public String name; private double salary; }
再來看下類變量賦值方法:
- 無final修飾,聲明時賦值,構造器中賦值,靜態語句塊或靜態方法賦值
- 有final修飾,聲明時賦值,聲明與賦值分開可在靜態語句塊中賦值
public class StaticTest { private static int staticInt = 2; private int random = 2; public StaticTest() { staticInt++; random++; } public static void main(String[] args) { System.out.println("類變量與對象變量的值變化"); StaticTest test = new StaticTest(); System.out.println(" 實例1:staticInt:" + test.staticInt + "----random:" + test.random); StaticTest test2 = new StaticTest(); System.out.println(" 實例2:staticInt:" + test.staticInt + "----random:" + test.random); System.out.println("靜態變量賦值"); System.out.println(" 靜態語句塊起作用:" + A.staticA); A a = new A(); System.out.println(" 構造器起作用:" + a.staticA); a.toChange(); System.out.println(" 靜態方法1起作用:" + A.staticA); a.toChange2(); System.out.println(" 靜態方法2起作用:" + A.staticA); System.out.println("常量賦值"); System.out.println(" 靜態語句賦值:" + B.staticB); } } class A { public static String staticA ="A" ; //靜態語句塊修改值 static{ staticA ="A1"; } //構造器修改值 public A (){ staticA ="A2"; } //靜態方法起作用 public static void toChange(){ staticA ="A3"; } public static void toChange2(){ staticA ="A4"; } } class B { public static final String staticB ; // 聲明與賦值分離 static{ staticB ="B"; } }
然后看下類變量與實例變量之間的區別:類變量可在類中直接使用,實例變量需實例化后才能使用。
public class StaticTest { private static int staticInt = 2; private int random = 2; public static void main(String[] args) { System.out.println(staticInt); StaticTest test = new StaticTest(); System.out.println(test.random); } }
再來看下成員變量,靜態變量,局部變量之間的區別:
|
成員變量 |
局部變量 |
靜態變量 |
定義位置 |
在類中,方法外 |
方法中,或者方法的形式參數 |
在類中,方法外 |
初始化值 |
有默認初始化值 |
無,先定義,賦值后才能使用 |
有默認初始化值 |
調用方式 |
對象調用 |
--- |
對象調用,類名調用 |
存儲位置 |
堆中 |
棧中 |
方法區 |
生命周期 |
與對象共存亡 |
與方法共存亡 |
與類共存亡 |
別名 |
實例變量 |
--- |
類變量 |
類的靜態數據成員值被所有對象共享,任何對象都可以訪問類的靜態數據成員。但是他們使用的是同一個數據,操作的是同一塊內存,無論哪個對象修改了它,對其他對象來說,他已經變了。
class A{ static int i; void change(int i1){i=i1;} } public class Test{ public static void main(String args[]){ A.i=10; A a=new A(); A b=new A(); System.out.println(A.i+","+a.i+","+b.i);//10,10,10 a.change(40); System.out.println(A.i+","+a.i+","+b.i);//40,40,40 b.i+=10; System.out.println(A.i+","+a.i+","+b.i);//50,50,50 } }
來解釋下:private static final double PI = 3.14;子類不可用(與類繼承關系) + 非靜態方法不可用(與方法的關系)+ 常量(與變量的關系) + 類型(與其他類型的關系)。
每次創建一個新對象就會分配一個實例變量,而始終只會分配一個靜態變量。看下面實例感受下:
public class Test { public static int staticVar=0;//靜態變量,加static關鍵字 public int instanceVar=0;//實例變量 public void VariantTest(){ staticVar++; instanceVar++; System.out.println("staticVar"+staticVar+",instanceVar="+instanceVar); } public static void main(String[] args) { for(int k=0;k<6;k++){ Test p=new Test(); p.VariantTest(); } } }
輸出結果為:
staticVar1,instanceVar=1 staticVar2,instanceVar=1 staticVar3,instanceVar=1 staticVar4,instanceVar=1 staticVar5,instanceVar=1 staticVar6,instanceVar=1
我們不可以從一個static方法內部發出對非static方法的調用。因為非static方法是要與對象關聯在一起的,必須創建一個對象后,才可以在該對象上進行方法調用,而static方法調用時不需要創建對象,可以直接調用。也就是說,當一個static方法被調用時,可能還沒有創建任何實例對象,如果從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪個對象上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的調用。來看下面的實例感受下:
public class Xix { // 靜態成員 public static String string="static成員"; // 普通成員 public String string2="非static成員"; // 靜態方法 public static void method(){ string="sss"; //string2="sss";編譯報錯,因為靜態方法里面只能調用靜態方法或靜態成員 //method2(); System.out.println("這是static方法,static方法與對象無關"); } // 普通方法 public void method2(){ string ="string1"; string2="string2"; method(); //非靜態方法里面可以發出對static方法的調用 System.out.println("這是非static方法,此方法必須和指定的對象關聯起來才起作用"); } public static void main(String[] args) { Xix x=new Xix(); x.method2();// 引用調用普通方法 x.method();// 引用調用靜態方法 } }
運行結果為:
這是static方法,static方法與對象無關 這是非static方法,此方法必須和指定的對象關聯起來才起作用 這是static方法,static方法與對象無關
package hello; //首先要知道變量應該是賦值以后才能使用的,但是有些不必人為賦值就有默認初始值,但是有些要人為定義初始值 //所以有些直接使用的並不是沒有賦值,而是系統自定義了初始值,所以不會報錯 public class Variable { public String instance = "實例變量"; public static String variable = "靜態變量"; //靜態變量的定義方式 public static String CONST = "靜態常量"; //靜態常量的定義方式 public static void main(String[] args) { String local = "局部變量"; //類似這個就是局部變量,不可用訪問修飾符修飾,沒有默認初始值 System.out.println(local); //局部變量就是在方法或語句塊中的變量 Global global = new Global(); //類似這個就是實例變量,也稱全局變量 System.out.println(global.instance); //實例變量就必須先把類new一個出來才能使用,因為他是在類中,方法外的 System.out.println(variable); //來瞅瞅靜態變量,也叫類變量,靜態變量的訪問方式1(在自己類的時候) System.out.println(Global.variable); //靜態變量的訪問方法2(不在自己類的時候) } } class Global{ public String instance = "實例變量"; //實例變量在一個類的里面,語句塊的外面 public static String variable = "靜態變量"; Global(){ //在類的內部使用自己的實例變量:要么老老實實new一個出來,就像上面那個 //第二種方法就是在函數里面使用實例變量,注意,如果方法是靜態方法參照方法1 System.out.println(instance); System.out.println(variable); } public void Instance() { System.out.println(instance); //靜態變量訪問方法1(在自己類的時候),靜態常量和靜態變量訪問相同 System.out.println(Variable.CONST); } }