欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java創(chuàng)建對(duì)象的四種方式詳解

 更新時(shí)間:2023年11月29日 08:48:31   作者:安然望川海  
這篇文章主要介紹了Java創(chuàng)建對(duì)象的四種方式詳解,如果我們不想利用默認(rèn)構(gòu)造器來創(chuàng)建java對(duì)象,而想利用指定的構(gòu)造器來創(chuàng)建java對(duì)象,則需要利用Construtor對(duì)象,每個(gè)Construtor對(duì)應(yīng)一個(gè)構(gòu)造器,需要的朋友可以參考下

前言

以String類為例

String string = null;
Class class1 = String.class;// 該方法最為安全可靠,程序性能更高。
Class class2 = string.getClass();
Class class3 = Class.forName(“java.lang.String”);// 可能拋出ClassNotFoundException異常

一旦獲取了該類所對(duì)應(yīng)的Class對(duì)象之后,就可以通過調(diào)用Class對(duì)象的方法來獲得該對(duì)象和該類的真實(shí)信息了

1. new 出一個(gè)對(duì)象

例:

String s = new String("abc");

2. 利用反射創(chuàng)建對(duì)象

1.創(chuàng)建對(duì)象

通過反射來生成對(duì)象有如下兩種方式:

(1)使用Class對(duì)象的newInstance()方法來創(chuàng)建該Class對(duì)象對(duì)應(yīng)類的實(shí)例。但是這種方式要求該Class對(duì)象的對(duì)應(yīng)類有默認(rèn)的構(gòu)造器,而執(zhí)行newInstance()方法時(shí)實(shí)際上是利用默認(rèn)構(gòu)造器來創(chuàng)建該類的實(shí)例。

(2)先使用Class對(duì)象獲取指定的Constructor對(duì)象,再調(diào)用Construtor對(duì)象的newInstance()方法來創(chuàng)建該Class對(duì)象對(duì)應(yīng)類的實(shí)例。通過這種方式可以選擇使用某個(gè)類的指定構(gòu)造器來創(chuàng)建實(shí)例。

另外,如果我們不想利用默認(rèn)構(gòu)造器來創(chuàng)建java對(duì)象,而想利用指定的構(gòu)造器來創(chuàng)建java對(duì)象,則需要利用Construtor對(duì)象,每個(gè)Construtor對(duì)應(yīng)一個(gè)構(gòu)造器,為了利用指定構(gòu)造器來創(chuàng)建java對(duì)象,需要如下三個(gè)步驟:

(1)獲取該Class對(duì)象;

(2)利用該Class對(duì)象的getConstrutor方法來獲取指定的構(gòu)造器;

(3)調(diào)用Construtor的newInstance方法來創(chuàng)建Java對(duì)象。

2.調(diào)用方法

獲取到某個(gè)類的Class對(duì)象之后,可以通過該Class對(duì)象的getMethods方法或者getMethod方法獲取全部或指定方法。

每個(gè)Method對(duì)象對(duì)應(yīng)一個(gè)方法,獲得Method對(duì)象后,程序就可通過該Method來調(diào)用對(duì)應(yīng)的方法,在Method里包含一個(gè)invoke方法,該方法簽名如下:

Object invoke(Object obj,Object… args);該方法中的obj是執(zhí)行該方法的主調(diào),后面的args是執(zhí)行該方法時(shí)傳入該方法的實(shí)參。

當(dāng)通過Method的invoke方法來調(diào)用對(duì)應(yīng)的方法時(shí),Java會(huì)要求程序必要要有調(diào)用該方法的權(quán)限。如果程序確實(shí)需要調(diào)用該對(duì)象的私有方法,則可先調(diào)用Method對(duì)象的:

setAccessible(boolean flag);方法,將Method對(duì)象的accessoble標(biāo)志設(shè)置為指示的布爾值。

布爾值為true,則表示該Method在使用時(shí)應(yīng)該取消Java語言訪問權(quán)限檢查;

布爾值為false,則表示該Method在使用時(shí)應(yīng)該實(shí)施Java語言訪問權(quán)限檢查;

3.訪問屬性值

通過Class對(duì)象的getFields或getField方法可以獲取該類所包括的全部Field(屬性)或指定Field,F(xiàn)ield提供了如下兩組方法來訪問屬性:

getXxx(Object obj);獲取obj對(duì)象該Field的屬性值,此處的Xxx對(duì)應(yīng)8個(gè)基本類型,如果該屬性的類型是引用類型則取消get后面的Xxx。

setXxx(Object obj,Xxx val);將obj對(duì)象的該Field設(shè)置成val值,此處的Xxx對(duì)應(yīng)8個(gè)基本類型,如果該屬性的類型是引用類型則取消set后面的Xxx。

4.示例代碼

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ClassTest {
    public static void main(String[] args) throws Exception {
        Object object;
        Class cl = Class.forName("TestMe");
        Method method = cl
                .getDeclaredMethod("print", new Class[]{String.class});
        Constructor constructor = cl
                .getDeclaredConstructor(new Class[]{String.class});
        object = constructor.newInstance(new Object[]{"Hello"});
        method.invoke(object, new Object[]{"zhouxianli"});
    }
}
class TestMe {
    private String str;
    public TestMe(String str) {
        this.str = str;
        System.out.println("In Constructor str = " + str);
    }
    public void print(String name) {
        System.out.println("In print str = " + str + " and name = " + name);
    }
} 

3. 利用clone創(chuàng)建對(duì)象

什么是"clone"?

在實(shí)際編程過程中,我們常常要遇到這種情況:有一個(gè)對(duì)象A,在某一時(shí)刻A中已經(jīng)包含了一些有效值,此時(shí)可能 會(huì)需要一個(gè)和A完全相同新對(duì)象B,并且此后對(duì)B任何改動(dòng)都不會(huì)影響到A中的值,也就是說,A與B是兩個(gè)獨(dú)立的對(duì)象,但B的初始值是由A對(duì)象確定的。在 Java語言中,用簡(jiǎn)單的賦值語句是不能滿足這種需求的。要滿足這種需求雖然有很多途徑,但實(shí)現(xiàn)clone()方法是其中最簡(jiǎn)單,也是最高效的手段。

Java的所有類都默認(rèn)繼承java.lang.Object類,在java.lang.Object類中有一個(gè)方法clone()。JDK API的說明文檔解釋這個(gè)方法將返回Object對(duì)象的一個(gè)拷貝。要說明的有兩點(diǎn):一是拷貝對(duì)象返回的是一個(gè)新對(duì)象,而不是一個(gè)引用。二是拷貝對(duì)象與用 new操作符返回的新對(duì)象的區(qū)別就是這個(gè)拷貝已經(jīng)包含了一些原來對(duì)象的信息,而不是對(duì)象的初始信息。

1. Clone&Copy

假設(shè)現(xiàn)在有一個(gè)Employee對(duì)象,Employee tobby =new Employee(“CMTobby”,5000),通 常我們會(huì)有這樣的賦值Employee cindyelf=tobby,這個(gè)時(shí)候只是簡(jiǎn)單了copy了一下reference,cindyelf和tobby都指向內(nèi)存中同一個(gè)object,這樣cindyelf或者tobby的一個(gè)操作都可能影響到對(duì)方。打個(gè)比方,如果我們通過cindyelf.raiseSalary()方法改變了salary域的值,那么tobby通過getSalary()方法得到的就是修改之后的salary域的值,顯然這不是我們?cè)敢饪吹降摹N覀兿M玫絫obby的一個(gè)精確拷貝,同時(shí)兩者互不影響,這時(shí)候我們就可以使用Clone來滿足我們的需求。Employee cindy=tobby.clone(),這時(shí)會(huì)生成一個(gè)新的Employee對(duì)象,并且和tobby具有相同的屬性值和方法。

2. Shallow Clone&Deep

Clone Clone是如何完成的呢?Object在對(duì)某個(gè)對(duì)象實(shí)施Clone時(shí)對(duì)其是一無所知的,它僅僅是簡(jiǎn)單地執(zhí)行域?qū)τ虻腸opy,這就是Shallow Clone。這樣,問題就來了咯,以Employee為例,它里面有一個(gè)域hireDay不是基本型別的變量,而是一個(gè)reference變量,經(jīng)過Clone之后就會(huì)產(chǎn)生一個(gè)新的Date型別的reference,它和原始對(duì)象中對(duì)應(yīng)的域指向同一個(gè)Date對(duì)象,這樣克隆類就和原始類共享了一部分信息,而這樣顯然是不利的,過程下圖所示:

在這里插入圖片描述

這個(gè)時(shí)候我們就需要進(jìn)行deep Clone了,對(duì)那些非基本型別的域進(jìn)行特殊的處理,例如本例中的hireDay。我們可以重新定義Clone方法,對(duì)hireDay做特殊處理,如下代碼所示:

class Employee implements Cloneable  
  
{  
        public Object clone() throws CloneNotSupportedException  
        {  
         Employee cloned = (Employee) super.clone();  
      cloned.hireDay = (Date) hireDay.clone()  
      return cloned;  
        }  
} 

3. Clone()方法的保護(hù)機(jī)制

在Object中Clone()是被申明為protected的,這樣做是有一定的道理的,以Employee

類為例,通過申明為protected,就可以保證只有Employee類里面才能“克隆”Employee對(duì)象,原理可以參考我前面關(guān)于public、protected、private的學(xué)習(xí)筆記。

4. Clone()方法的使用

Clone()方法的使用比較簡(jiǎn)單,注意如下幾點(diǎn)即可:

a. 什么時(shí)候使用shallow Clone,什么時(shí)候使用deep Clone,這個(gè)主要看具體對(duì)象的域是什么性質(zhì)的,基本型別還是reference variable

b. 調(diào)用Clone()方法的對(duì)象所屬的類(Class)必須implements Clonable接口,否則在調(diào)用Clone方法的時(shí)候會(huì)拋出CloneNotSupportedException。

4. 利用反序列化創(chuàng)建對(duì)象

1、為什么要進(jìn)行序列化

再介紹之前,我們有必要先了解下對(duì)象的生命周期,我們知道Java中的對(duì)象都是存在于堆內(nèi)存中的,而堆內(nèi)存是可以被垃圾回收器不定期回收的。從對(duì)象被創(chuàng)建到被回收這一段時(shí)間就是Java對(duì)象的生命周期,也即Java對(duì)象只存活于這個(gè)時(shí)間段內(nèi)。

對(duì)象被垃圾回收器回收意味著對(duì)象和對(duì)象中的成員變量所占的內(nèi)存也就被回收,這意味著我們就再也得不到該對(duì)象的任何內(nèi)容了,因?yàn)橐呀?jīng)被銷毀了嘛,當(dāng)然我們可以再重新創(chuàng)建,但這時(shí)的對(duì)象的各種屬性都又被重新初始化了。所以如果我們需要保存某對(duì)象的狀態(tài),然后再在未來的某段時(shí)間將該對(duì)象再恢復(fù)出來的話,則必須要在對(duì)象被銷毀即被垃圾回收器回收之前保存對(duì)象的狀態(tài)。要保存對(duì)象狀態(tài)的話,我們可以使用文件、數(shù)據(jù)庫,也可以使用序列化,這里我們主要介紹對(duì)象序列化。我們很有必要了解這方面的內(nèi)容,因?yàn)閷?duì)象序列化不僅在保存對(duì)象狀態(tài)時(shí)可以被用到(對(duì)象持久化),在Java中的遠(yuǎn)程方法調(diào)用RMI也會(huì)被用到,在網(wǎng)絡(luò)中要傳輸對(duì)象的話,則必須要對(duì)對(duì)象進(jìn)行序列化,關(guān)于RMI有機(jī)會(huì)我會(huì)再專門開貼介紹。

簡(jiǎn)單總結(jié)起來,進(jìn)行對(duì)象序列化的話的主要原因就是實(shí)現(xiàn)對(duì)象持久化和進(jìn)行網(wǎng)絡(luò)傳輸,這里先只介紹怎樣通過對(duì)象序列化保存對(duì)象的狀態(tài)。

下面我們通過一個(gè)簡(jiǎn)單的例子來介紹下如何進(jìn)行對(duì)象序列化。

2、怎樣進(jìn)行對(duì)象序列化

假設(shè)我們要保存Person類的某三個(gè)對(duì)象的name、age、height這三個(gè)成員變量,當(dāng)然這里只是簡(jiǎn)單舉例

我們先看下Person類,要序列化某個(gè)類的對(duì)象的話,則該類必要實(shí)現(xiàn)Serializable接口,從Java API中我們發(fā)現(xiàn)該接口是個(gè)空接口,即該接口中沒聲明任何方法。

import java.io.Serializable;  
public class Person implements Serializable {  
int age;  
int height;  
String name;  
public Person(String name, int age, int height){  
this.name = name;  
this.age = age;  
this.height = height;  
}  
}  

下面我們看一下如何來進(jìn)行序列化,這其中主要涉及到 Java 的 I/O 方面的內(nèi)容,主要用到兩個(gè)類 FileOutputStream 和 ObjectOutputStream , FileOutputStream 用于將字節(jié)輸出到文件, ObjectOutputStream 通過調(diào)用 writeObject 方法將對(duì)象轉(zhuǎn)換為可以寫出到流的數(shù)據(jù)。所以整個(gè)流程是這樣的: ObjectOutputStream 將要序列化的對(duì)象轉(zhuǎn)換為某種數(shù)據(jù),然后通過 FileOutputStream 連接某磁盤文件,再對(duì)象轉(zhuǎn)化的數(shù)據(jù)轉(zhuǎn)化為字節(jié)數(shù)據(jù)再將其寫出到磁盤文件。下面是具體代碼:

import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectOutputStream;  
public class MyTestSer {  
/** 
 * Java對(duì)象的序列化與反序列化 
 */  
public static void main(String[] args) {  
Person zhangsan = new Person("zhangsan", 30, 170);  
Person lisi = new Person("lisi", 35, 175);  
Person wangwu = new Person("wangwu", 28, 178);  
try {  
//需要一個(gè)文件輸出流和對(duì)象輸出流;文件輸出流用于將字節(jié)輸出到文件,對(duì)象輸出流用于將對(duì)象輸出為字節(jié)  
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser"));  
out.writeObject(zhangsan);  
out.writeObject(lisi);  
out.writeObject(wangwu);  
out.close();  
} catch (IOException e) {  
e.printStackTrace();  
}  
}  
}  

3、對(duì)象的反序列化

我們存儲(chǔ)的目的主要是為了再恢復(fù)使用,下面我們來看下加上反序列化后的代碼:

import java.io.FileInputStream;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
public class MyTestSer {  
/** 
 * Java對(duì)象的序列化與反序列化 
 */  
public static void main(String[] args) {  
Person zhangsan = new Person("zhangsan", 30, 170);  
Person lisi = new Person("lisi", 35, 175);  
Person wangwu = new Person("wangwu", 28, 178);  
try {  
//需要一個(gè)文件輸出流和對(duì)象輸出流;文件輸出流用于將字節(jié)輸出到文件,對(duì)象輸出流用于將對(duì)象輸出為字節(jié)  
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser"));  
out.writeObject(zhangsan);  
out.writeObject(lisi);  
out.writeObject(wangwu);  
} catch (IOException e) {  
e.printStackTrace();  
}  
try {  
ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.ser"));  
Person one = (Person) in.readObject();  
Person two = (Person) in.readObject();  
Person three = (Person) in.readObject();  
System.out.println("name:"+one.name + " age:"+one.age + " height:"+one.height);  
System.out.println("name:"+two.name + " age:"+two.age + " height:"+two.height);  
System.out.println("name:"+three.name + " age:"+three.age + " height:"+three.height);  
} catch (Exception e) {  
e.printStackTrace();  
}  
}  
}  

輸出結(jié)果如下:

name:zhangsan age:30 height:170  
name:zhangsan age:35 height:175  
name:zhangsan age:28 height:178  

從添加的代碼我們可以看到進(jìn)行反序列化也很簡(jiǎn)單,主要用到的流是FileInputstream和ObjectInputstream正好與存儲(chǔ)時(shí)用到的流相對(duì)應(yīng)。另外從結(jié)果順序我們可以看到反序列化后得到對(duì)象的順序與序列化時(shí)的順序一致。

4、總結(jié)

進(jìn)行對(duì)象序列化主要目的是為了保存對(duì)象的狀態(tài)(成員變量)。

進(jìn)行序列化主要用到的流是FileOutputStream和ObjectOutputStream。FileOutputStream主要用于連接磁盤文件,并把字節(jié)寫出到該磁盤文件;ObjectOutputStream主要用于將對(duì)象寫出為可轉(zhuǎn)化為字節(jié)的數(shù)據(jù)。

要將某類的對(duì)象序列化,則該類必須實(shí)現(xiàn)Serializable接口,該接口僅是一個(gè)標(biāo)志,告訴JVM該類的對(duì)象可以被序列化。如果某類未實(shí)現(xiàn)Serializable接口,則該類對(duì)象不能實(shí)現(xiàn)序列化。

保存狀態(tài)的目的就是為了在未來的某個(gè)時(shí)候再恢復(fù)保存的內(nèi)容,這可以通過反序列化來實(shí)現(xiàn)。對(duì)象的反序列化過程與序列化正好相反,主要用到的兩個(gè)流是FileInputstream和ObjectInputStream。

反序列化后得到的對(duì)象的順序與保存時(shí)的順序一致。

5、補(bǔ)充

補(bǔ)充一:上面我們舉得例子很簡(jiǎn)單,要保存的成員變量要么是基本類型的要么是String類型的。但有時(shí)成員變量有可能是引用類型的,這是的情況會(huì)復(fù)雜一點(diǎn)。那就是當(dāng)要對(duì)某對(duì)象進(jìn)行序列化時(shí),該對(duì)象中的引用變量所引用的對(duì)象也會(huì)被同時(shí)序列化,并且該對(duì)象中如果也有引用變量的話則該對(duì)象也將被序列化??偨Y(jié)說來就是在序列化的時(shí)候,對(duì)象中的所有引用變量所對(duì)應(yīng)的對(duì)象將會(huì)被同時(shí)序列化。這意味著,引用變量類型也都要實(shí)現(xiàn)Serializable接口。當(dāng)然其他對(duì)象的序列化都是自動(dòng)進(jìn)行的。所以我們只要保證里面的引用類型是都實(shí)現(xiàn)Serializable接口就行了,如果沒有的話,會(huì)在編譯時(shí)拋出異常。如果序列化的對(duì)象中包含沒有實(shí)現(xiàn)Serializable的成員變量的話,這時(shí)可以使用transient關(guān)鍵字,讓序列化的時(shí)候跳過該成員變量。使用關(guān)鍵字transient可以讓你在序列化的時(shí)候自動(dòng)跳過transient所修飾的成員變量,在反序列化時(shí)這些變量會(huì)恢復(fù)到默認(rèn)值。

補(bǔ)充二:如果某類實(shí)現(xiàn)了Serializable接口的話,其子類會(huì)自動(dòng)編程可序列化的,這個(gè)好理解,繼承嘛。

補(bǔ)充三:在反序列化的時(shí)候,并不會(huì)調(diào)用對(duì)象的構(gòu)造器,這也好理解,如果調(diào)用了構(gòu)造器的話,對(duì)象的狀態(tài)不就又重新初始化了嗎。

補(bǔ)充四:我們說到對(duì)象序列化的是為了保存對(duì)象的狀態(tài),即對(duì)象的成員變量,所以靜態(tài)變量不會(huì)被序列化。

到此這篇關(guān)于Java創(chuàng)建對(duì)象的四種方式詳解的文章就介紹到這了,更多相關(guān)Java創(chuàng)建對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

  • JavaWeb搭建網(wǎng)上圖書商城畢業(yè)設(shè)計(jì)

    JavaWeb搭建網(wǎng)上圖書商城畢業(yè)設(shè)計(jì)

    這篇文章主要介紹了JavaWeb搭建網(wǎng)上圖書商城框架,特別適合正在為網(wǎng)上商城畢業(yè)設(shè)計(jì)煩惱的同學(xué),需要的朋友可以參考下
    2015-11-11
  • Spring AOP 切面@Around注解的用法說明

    Spring AOP 切面@Around注解的用法說明

    這篇文章主要介紹了Spring AOP 切面@Around注解的用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 新手了解java基礎(chǔ)知識(shí)(一)

    新手了解java基礎(chǔ)知識(shí)(一)

    這篇文章主要介紹了Java基礎(chǔ)知識(shí),本文介紹了Java語言相關(guān)的基礎(chǔ)知識(shí)、歷史介紹、主要應(yīng)用方向等內(nèi)容,需要的朋友可以參考下,希望對(duì)你有所幫助
    2021-07-07
  • SpringBoot啟動(dòng)器Starters使用及原理解析

    SpringBoot啟動(dòng)器Starters使用及原理解析

    這篇文章主要介紹了SpringBoot啟動(dòng)器Starters使用及原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • MyBatisPlus?TypeHandler自定義字段類型轉(zhuǎn)換Handler

    MyBatisPlus?TypeHandler自定義字段類型轉(zhuǎn)換Handler

    這篇文章主要為大家介紹了MyBatisPlus?TypeHandler自定義字段類型轉(zhuǎn)換Handler示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對(duì)比

    后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對(duì)比

    這篇文章主要給大家介紹了關(guān)于后端返回各種圖片形式在前端的轉(zhuǎn)換及展示方法對(duì)比的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-06-06
  • java操作elasticsearch詳細(xì)方法總結(jié)

    java操作elasticsearch詳細(xì)方法總結(jié)

    elasticsearch是使用Java編寫的一種開源搜索引擎,也是一種分布式的搜索引擎架構(gòu),這篇文章主要給大家介紹了關(guān)于java操作elasticsearch的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • C#創(chuàng)建Web應(yīng)用程序代碼實(shí)例

    C#創(chuàng)建Web應(yīng)用程序代碼實(shí)例

    本文主要通過實(shí)例代碼介紹了C#創(chuàng)建Web應(yīng)用程序,需要的朋友可以參考下
    2017-04-04
  • SpringBoot使用Async注解失效原因分析及解決(spring異步回調(diào))

    SpringBoot使用Async注解失效原因分析及解決(spring異步回調(diào))

    這篇文章主要介紹了SpringBoot使用Async注解失效原因分析及解決(spring異步回調(diào)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 最新評(píng)論