詳解Java的對象創建


1. 前言

《還不清楚怎樣面向對象?》《面向對象再探究》兩篇文章中,都介紹了關於面向對象程序設計的概念和特點。其中也涉及到了許多代碼,比如:

Dog dog = new Dog();

這篇文章就主要來談談創建對象時的具體操作。

2. 引入例子

下面是一個Dog類:

/**
 * @author Xing Xiaoguan (xingrenguanxue)
 */

public class Dog {
    private String name;
    private int age;
    private String address;
    
    public void say() {
        System.out.println("我叫" + name + ",今年" + age + "歲了,家住" + address + ",汪汪汪...");
    }

	//getters 和 setters
}

下面是一個Test類,創建了一個Dog對象,然后進行相關操作:

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("哮天犬");
        dog.setAge(1);
        dog.setAddress("光明小區")
        dog.say();
    }
}

輸出:

我叫小黑,今年1歲了,家住光明小區,汪汪汪...

3. 對象和對象變量

對象是根據類創造出來的,我們使用的是具體的對象,而不是類。要想使用對象,那對象必須得先被創建出來才行。下面一行代碼是創建對象的語句:

Dog dog = new Dog();

我們將其分成三部分來看:

(1)new :如果你想創建一個對象,那么必須使用new操作符。

(2)Dog():這是一個構造器,構造器是一個特殊的方法。通過調用該構造器,我們可以創建並初始化一個對象出來。

new Dog()連起來就能正確地創建出一個對象了。但是我們創造出來的對象並不只會使用一次,而會使用許多次,所以我們需要給該對象 “取一個名字”,保證它“隨叫隨到”。這就需要第三部分了:

(3)Dog dog:聲明一個Dog類型的、名為dog的變量。它就類似於int number,聲明一個int類型的number變量。

然后我們使用=進行賦值(引用),便給創建出的對象 “取一個名字”dog,以后可以稱它為dog對象。

這里可能會出現一個誤區,認為:Dog dog部分便能創建出一個dog對象,這是錯誤的。應當明確:dog從頭到尾都只是一個變量而已。這個變量和使用int numberString str等方式聲明的變量,除了類型不同之外並無差別。

真正創建出對象的是new Dog()部分。

下面解釋一下 “取一個名字” 是什么意思。

在Java中,對象變量中存儲的並不是對象,真正的變量在內存的某個地方躺着呢。該變量記錄的是對象在內存中的位置,我們有了對象變量,就有了對象的位置,有了位置,就能找到真正的對象。

看下面的代碼:

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();//創建出一個dog對象
        System.out.println(dog);//打印dog
    }
}
打印結果:basic.Dog@1b6d3586

1b6d3586便是dog對象在內存中的地址。

4. 構造器

前面提到,創建一個對象的關鍵在於使用new操作符和構造器。構造器是一個特殊的方法,通過調用構造器,我們可以創建並初始化一個對象出來。

構造器的特點:

  1. 有一個訪問修飾符
  2. 構造器的名字和類名相同
  3. 構造器沒有返回值
  4. 構造器要和new操作符一起使用
  5. 構造器可以有0個、1個或多個構造器
  6. 一個類中可以有多個構造器

4.1. 無參構造器

即沒有參數的構造器,如Dog()。無參構造器是Java默認的構造器,如果你在編寫類時沒有寫構造器,那么Java會在類中默認提供一個無參構造器。

Dog類中並沒有寫構造器,Dog類默認擁有下面的無參構造器:

public Dog() {
    
}

4.2. 有參構造器

有參構造器,即有參數的構造器。例如:

public Dog(String n, int a, String addr) {
    name = n;
    age = a;
    address = addr;
}

這個有參構造器非常簡單,分別給na參數傳值,然后給對象的屬性賦值。美中不足的是參數的變量名取得不夠“見名知意”,所以我們通常這樣寫:

public Dog(String name, int age, String address) {
    this.name = name;
    this.age = age;
    this.address = address;
}

參數的名字和對象的成員變量名一樣,這樣,參數的意義就很清晰了。在賦值的時候,使用this關鍵字區分二者,因為this代表我們所創建的對象,this.name即對象的成員變量。

有了有參構造器,我們就可以在創建對象時初始化對象的屬性,比如:

public static void main(String[] args) {
    Dog dog = new Dog("小狗有參", 1, "地球");
    dog.say();
}

輸出:

我叫小狗有參,今年1歲了,家住地球,汪汪汪...

4.3. 多個構造器的使用

先了解一個概念——重載(overloading)。重載是指在一個類中,有幾個方法的方法名字相同,而參數不同。返回值類型可以相同也可以不相同。注意:每個重載的方法的參數列表必須獨一無二

注意:參數列表的獨一無二是指參數列表的類型的獨一無二

千萬不要以為func(String name)func(String address)這兩個方法的參數列表是不同的。它倆應該這樣看:func(String)func(String),所以這倆方法是相同的

下圖是String類中的部分方法的重載情況,可從中體會參數列表的獨一無二:

為什么要求參數列表必須獨一無二呢?

這就得介紹另一個概念——方法的簽名。方法的簽名是指要完整地描述一個方法,需要指出方法名參數類型。注意:方法的返回類型不是簽名的一部分。

所以在Java中,方法名和參數列表能確定一個方法。不存在方法名和參數列表相同,而返回類型不同的方法們。

而重載要求的是方法名相同,參數列表不同。從方法的簽名角度來看,重載方法之間本就是不同的方法。

由於重載的存在,我們可以在一個類中編寫多個參數列表不同的構造器,使該類具有多種創建對象的形式。比如:

public class Dog {
    private String name;
    private int age;
    private String address;
    
    public Dog() {//無參構造器,有其他構造器存在,系統不會默認提供

    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Dog(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    public void say() {
        System.out.println("我叫" + name + ",今年" + age + "歲了,家住" + address + ",汪汪汪...");
    }

	//getters 和 setters
}

寫了三種構造器,便有三種創建對象的方式:

Dog dog = new Dog("小狗", 1, "太陽系");
Dog dog1 = new Dog("小狗1", 2);
Dog dog2 = new Dog();

編譯器會根據我們提供的參數匹配到合適的構造器。

注意:無參構造器只有在我們沒有編寫任何構造器時,系統才會默認提供。所以當一個類中有其他構造器時,如果我們需要無參構造器,那么必須手動編寫出來,系統不會默認提供。

4.4. 構造器之間的關系

在類中,一個構造器可以調用另一個構造器。如下例:

/**
 * @author Xing Xiaoguan (xingrenguanxue)
 */

public class Dog {
    private String name;
    private int age;
    private String address;

    public Dog(String name, int age) {
        this(name, age, "銀河系");//調用另一個構造器
        System.out.println("兩個參數的構造器");
    }

    public Dog(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
        System.out.println("三個參數的構造器");
    }
    
    public void say() {
        System.out.println("我叫" + name + ",今年" + age + "歲了,家住" + address + ",汪汪汪...");
    }

	//getters and setters...
}

使用Dog(String, int)創建對象:

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("小狗有參", 1);
        dog.say();
    }
}

輸出:

三個參數的構造器
兩個參數的構造器
我叫小狗有參,今年1歲了,家住銀河系,汪汪汪...

我們在構造器的第一行語句中使用this(...)來調用另一個構造器。注意:一定要是第一行語句。

5. 對象屬性的初始化

所謂初始化,就是我們在創建對象同時設置對象的屬性值。

5.1. 默認的屬性值

當我們創建對象時如果不顯式地設置屬性值,對象的屬性值會被初始化為默認值。

數值的默認值為0,布爾值的默認值為false,對象引用的默認值為null

如下例中的Dog類的屬性值:

public class Dog {
    private String name;
    private int age;
    private String address;
    
    public void say() {
        System.out.println("我叫" + name + ",今年" + age + "歲了,家住" + address + ",汪汪汪...");
    }
} 

創建對象:

public static void main(String[] args) {
    Dog dog = new Dog();
    dog.say();
}

輸出:

我叫null,今年0歲了,家住null,汪汪汪...

5.2. 直接設置屬性值

我們可以在類中直接設置類的屬性值,這樣一來,根據該類創建的對象的屬性值就確定了。

如下例中Dog類的屬性值:

public class Dog {
    private String name = "小黑";
    private int age = 2;
    private String address = "太陽系";
    
    public void say() {
        System.out.println("我叫" + name + ",今年" + age + "歲了,家住" + address + ",汪汪汪...");
    }
} 

這時再創建對象:

public static void main(String[] args) {
    Dog dog = new Dog();
    dog.say();
}

輸出:

我叫小黑,今年2歲了,家住太陽系,汪汪汪...

5.3. 使用構造器初始化

(一) 當構造器中沒有顯式地設置對象的屬性值時,這些屬性值會被初始化為默認值。如下面的無參構造器:

public Dog() {
    
}

創建對象:

public static void main(String[] args) {
    Dog dog = new Dog();
    dog.say();
}

輸出:

我叫null,今年0歲了,家住null,汪汪汪...

(二)可以在無參構造器的方法體中初始化屬性值:

public Dog() {
    name = "小黑";
    age = 2;
    address = "宇宙";
}

創建對象:

public static void main(String[] args) {
    Dog dog = new Dog();
    dog.say();
}

輸出:

我叫小黑,今年2歲了,家住宇宙,汪汪汪...

(三)也可以使用有參構造器,對象會按照我們傳入的變量初始化屬性值:

public Dog(String name, int age, String address) {
    this.name = name;
    this.age = age;
    this.address = address;
}

創建對象:

public static void main(String[] args) {
    Dog dog = new Dog("小黑", 3, "南極");
    dog.say();
}

輸出:

我叫小黑,今年3歲了,家住南極,汪汪汪...

如有錯誤,還請指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM