1. 程式人生 > 實用技巧 >面向物件中的變數和執行機制及自動裝拆箱

面向物件中的變數和執行機制及自動裝拆箱

成員變數和區域性變數及執行機制

兩者的區別在於定義變數的位置不同,執行的機制也有差異。成員變數定義在類中,區域性變數定義在定義在方法中。

成員變數分為類變數和例項變數兩種,區域性變數分為形參(方法內)、方法區域性變數和程式碼塊內區域性變數,比如迴圈內的。

類變數的生命週期和類一樣,從類準備階段開始,到完全銷燬這個類,作用域則與類的生存範圍相同。而例項變數從例項被建立起開始存在,直到例項被銷燬,作用域對應例項作用域。可以發現,成員變數之所以稱為成員變數,是因為其與所在的整體共存亡的。

注意:類變數是屬於類的,通過例項.類變數訪問的依然是類變數,如果該例項修改了變數值,則其他例項訪問時也將使用修改過的變數值。即訪問了同一片記憶體區!

與成員變數不同,區域性變數除了形參外,都必須顯式初始化;而上面的成員變數可以進行預設初始化,賦值規則與陣列動態初始化時賦值規則相同。

當通過類或物件呼叫某個方法時,系統1會在呼叫該方法棧區內為所有形參分配記憶體,並將實參值賦值給對應形參,即完成形參初始化。

Java允許區域性變數和成員變數同名,如果需要在方法內引用被覆蓋的成員變數(區域性變數和成員變數同名),可以使用this關鍵字。

public class Test{
    public String name = "猴子";
    public static int age = 500;
    public void outPut(){
        String name = "悟空";
        System.out.println(name);//"悟空"
        System.out.println(this.name);//"猴子"
    }
    public static void main(String[] args){
        double age = 100000.0;
        System.out.println(age);//100000.0
        System.out.println(Test.age);//500
        new Test().outPut();
    }
}

成員、區域性變數初始化及執行機制

在類初始化或物件初始化時,系統會為成員變數分配記憶體空間,並指定預設初始值。需要關注的是,在建立一個物件時,不需要給類變數分配記憶體空間,只是為例項變數分配記憶體空間,因為類初始化時已經分配好了。在建立多個物件時,同樣如此,也需要為例項變數分配記憶體空間,而且,例項變數是單個例項的,與類或其他例項無關。

區域性變數定義後,必須經過顯式初始化後才能使用,系統不會為區域性變數執行初始化,就不會為變數分配記憶體空間,直到變數被初始化。與成員變數不同,區域性變數不屬於任何例項或類,因此它被儲存在所在的方法棧中。如果變數是基本型別的變數,則會把值直接儲存在對應記憶體中;但是變數是引用型別

,則它存放的是地址,地址是所引用的物件或陣列的地址。

區域性變數的生命週期是和方法或程式碼塊一致,但所在棧記憶體無需垃圾回收,因為區域性變數只儲存基本型別的值或引用,所以所佔記憶體比較小。

包裝類

基本資料型別不具備物件特性:無成員變數,方法被呼叫。但有些時候顯得不那麼好,比如方法需要object型別的引數,並且需要提供實際值,像2,3,4,這就麻煩了。Java提供了包裝類概念,併為8種基本資料型別定義了引用型別(基本資料型別的包裝類)。

基本資料型別 包裝類
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean

上述除Character外,其他包裝類可傳入引數建立一個包裝類物件,

由於基本資料型別和包裝類物件之間轉換麻煩,JDK1.5提供了自動裝箱和拆箱功能,去解決該問題。

自動裝箱:基本型別變數賦值給包裝類(或者Object變數);自動拆箱:包裝類物件賦值給基本型別變數

Integer a = 5;//基本型別賦值給Integer物件
Object b = true;//把布林型別賦值給Object物件
int c = a;//Integer物件拆箱賦值給基本型別

雖然包裝類是引用型別,但是例項是可以與數值比較的,比較時直接取出包裝類的值進行比較。而包裝類物件之間比較,只有指向同一物件時返回true。

System.out.println(new Integer(1) == new Integer(1));//false
Integer a = 6;
Integer b = 6;
System.out.println(a == b);//true,待會解釋
//注意,Integer資料範圍在-128~127之間,若不在會重新建立例項

從上面來看,系統將整數裝箱成例項,會放入一個cache陣列(長度為256,Java就是這樣設計的)中快取起來,以後如需自動裝箱則直接指向陣列元素(若在-128~127之間),即引用同一個例項物件。這樣的快取設計有利程式的執行效能,節省開銷。

字串與基本型別的轉換

字串轉基本型別有兩種方式:

  1. 包裝類的parseXxx(String s)方法(除了Character包裝類外)
  2. 對應的構造器方法,Xxx(String s)

基本型別轉字串則使用String的多個過載valueOf方法。上述程式碼示例:

String str = "123";
int a = Integer.parseInt(str);//第一種方法
int b = new Integer(str);//構造器建立物件,之後拆箱賦值給變數b
//基本資料型別轉字串
String str1 = String.valueOf(3.14159f);
String str2 = String.valueOf(true);

Java7、8增強包裝類

Java7開始為所有包裝類提供靜態的compare(v1,v2)方法,則可以通過該方法比較基本值的大小。比如:

System.out.println(Boolean.compare(true,false));//1
System.out.println(Boolean.compare(true,true));//0
System.out.println(Boolean.compare(false,true));//-1

Java8再次增強,開始支援無符號算術運算。如為Integer、Long增強了靜態的toUnsignedString(int/long v)整型轉化成無符號整數對應的字串、toUnsignedString(int/long v,int radix)轉化成指定進位制無符號整數對應的字串。

無符號整數的二進位制最高位不再當作符號位看,即最小值為0。例如-2,對應的無符號整數為252


公眾號: 菜雞幹Java
流浪舟 https://index.maliaoblog.cn