Java 建立類的四種方式

APP創意實驗室發表於2020-10-11

Java 建立類的四種方式

對於上學期已經學習過c++的同學,是不是對另一大程式語言產生了濃厚的興趣,對於c++的物件導向程式設計,又和java的面向變數有何區別,下面我們從java四種建立物件來說起。

一:new運算的方式建立物件
首先我們有一個關於寵物的類Dog
在這裡插入圖片描述
當我們程式中需要出現一隻狗狗的時候,我們就可以使用new來建立一個具體的物件了
在這裡插入圖片描述
我們祥和裡通過了new的方式獲得了一個具體的物件,小黑年齡時是三歲。

二:通過反射的方式建立物件
Java的反射技術是java程式的特徵之一,它允許執行中的Java程式對自身進行檢查,或者說“自審”,並能直接操作程式的內部屬性。
反射的作用:
1)可以通過反射機制發現物件的型別,找到類中包含的方法、屬性和構造器
2)可以通過反射建立物件並訪問任意物件方法和屬性

第二種建立java物件的方式就是通過反射來建立了。
還是我們之前用過的Dog類,首先JVM利用ClassLoader(類載入器)先將Dog類載入到記憶體,然後馬上產生了一個Class型別的物件,該物件可以看成是一個模型,以後無論建立多少個Dog類的例項都是利用該模型來生成(一個類所對應的Class型別的物件只有一個)。
通過反射建立物件第一步:需要獲得class物件

Class clazz = Dog.class;

這樣獲取到類物件之後就可以通過newInstance()這個方法來獲取具體的物件了,需要注意的是這個方法的返回值是Object型別,我們需要進行轉型操作

Class clazz = Dog.class;
Dog dog = (Dog)clazz.newInstance();

這樣我們就通過反射的方式建立好了java物件,newInstance()和new的區別如下:
newInstance: 弱型別。低效率。只能呼叫無參構造。
new: 強型別。相對高效。能呼叫任何public構造。

在這裡需要注意的是,newInstance()這個方法只能夠呼叫無參的建構函式(其實這也符合javabean規範,一個類必須擁有一個無參建構函式),現在我們在Dog類中寫有參建構函式(預設覆蓋無參建構函式),值得注意的是,當我們寫了有參建構函式之後,系統將不再提供預設的無參建構函式,如果需要的話,需要你自己寫

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

現在再去呼叫newInstance()方法
Class clazz=Dog.class;
Dog dog=(Dog) clazz.newInstance();

現在程式執行結果為java.lang.InstantiationException,著就是程式沒有無參建構函式而使用newInstance()方法引發的錯誤了
當然如果你需要呼叫有參建構函式的話,可以通過以下的辦法:

Class clazz=Dog.class;
Constructor constructor=clazz.getConstructor(String.class,int.class});
Dog dog=(Dog) constructor.newInstance("xiaohei",3});
System.out.println(dog.name+" "+dog.age);

程式的第二行我們呼叫Class物件的getConstructor方法,然後在引數列表中傳入String和int,因為我們的有參建構函式的引數列表就是這樣規定的,現在我們就獲取到了前邊定義好的Dog類的有參建構函式了

第三行我們通過獲取的Constructor物件呼叫newInstance方法,然後在方法中傳入Object型別的引數列表,因為我們的有參建構函式需要這些值,這樣就可以通過反射的方式建立只有有參建構函式的物件了

三:通過物件反序列化的方式來建立
當我們使用反序列化一個物件的時候,JVM會給我們建立一個物件。但是,反序列化的時候JVM並不會去呼叫類的建構函式(前邊兩種方式都會去呼叫建構函式)來建立物件,而是通過之前序列化物件的位元組序列來建立的。

序列化物件必須實現Serializable這個介面
把物件轉為位元組序列的過程稱為物件的序列化
把位元組序列恢復為物件的過程稱為物件的反序列化

public class Dog implements Serializable{
String name;
int age;
public void show(){
System.out.println("我叫"+this.name+"今年"+this.age+"歲了");
}
}

需要注意的是:Dog類需要實現Serializable這個介面才可以被序列化/反序列化,否則會出現java.io.NotSerializableException異常
物件序列化通常有兩種用途:
1)將物件的位元組序列永久的儲存到硬碟上
例如web伺服器把某些物件儲存到硬碟讓他們離開記憶體空間,節約記憶體,當需要的時候再從硬碟上取回到記憶體中使用
2)在網路上傳遞位元組序列
當兩個程式進行遠端通訊的時候,傳送方將java物件轉換成位元組序列傳送(序列化),接受方再把這些位元組序列轉換成java物件(反序列化)
當Dog類實現了Serializable介面後,我們現在將Dog物件序列化

1
2
3
4
5
6
7
Dog dog=new Dog();
dog.name="xiaohei";
dog.age=3;
FileOutputStream fos = new FileOutputStream("dog.txt");
ObjectOutputStream ops = new ObjectOutputStream(fos);
ops.writeObject(dog);
System.out.println("dog物件序列化完成");

通過ObjectOutputStream的writeObject方法,我們就將一個物件完成了序列化

現在我們再次將剛才序列化後的物件反序列化回來,這次用到的是ObjectInputStream的readObject方法:

1
2
3
4
5
FileOutputStream fos=new FileOutputStream("dog.txt");
ObjectInputStream ois=new ObjectInputStream(fos);
Dog dog=(Dog) ois.readObject();
System.out.println("我叫"+dog.name+"今年"+dog.age+"歲了");
System.out.println("物件反序列化完成");

這樣我們就使用了物件的序列化完成了java物件的建立

四:通過clone的方式來建立
clone方法來源於java中object類,在jdk中的解釋為:該方法返回一個此物件的副本。clone顧名思義就是複製的意思。所謂複製物件就是在記憶體中分配一個和原一模一樣的空間,在此建立新的物件。

我們現在就來完成clone的實驗,首先我們需要在需要clone的類中實現Cloneable介面,否則會出現java.lang.CloneNotSupportedException異常,由於Object類中clone方法是protected 修飾的,所以我們必須在需要克隆的類中重寫克隆方法

public class Dog implements Cloneable{
String name;
int age;
@Override
protected Object clone() throws CloneNotSupportedException {
//TODO Auto-generated method stub
return super.clone();
}
}

現在進入實驗1Dog d1=new Dog();
Dog d2=d1;
System.out.println(d1==d2);

返回值為true,因為在這個地方只有d1是真實建立了物件,d2來源於d1的賦值,引用地址值一樣(代表是同一個物件),所以==判斷結果為true

現在進入實驗2:

Dog d1=new Dog();
Dog d2=(Dog) d1.clone();
System.out.println(d1==d2);

實驗結果為false,因為clone是真實在記憶體中重新劃分一塊區域來儲存新的物件,d1和d2是兩個不同的物件所以返回結果值為false
這樣我們就使用了物件的克隆的方式完成了java物件的建立
值得一提的是
Java物件種通過new出來的是管理者
而c加加中new出來的是獨立的
今天的分享到此結束。

相關文章