最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2023年11月29日 08:48:31   作者:安然望川海  
這篇文章主要介紹了Java創(chuàng)建對象的四種方式詳解,如果我們不想利用默認(rèn)構(gòu)造器來創(chuàng)建java對象,而想利用指定的構(gòu)造器來創(chuàng)建java對象,則需要利用Construtor對象,每個(gè)Construtor對應(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異常

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

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

例:

String s = new String("abc");

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

1.創(chuàng)建對象

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

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

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

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

(1)獲取該Class對象;

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

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

2.調(diào)用方法

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

每個(gè)Method對象對應(yīng)一個(gè)方法,獲得Method對象后,程序就可通過該Method來調(diào)用對應(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)用對應(yīng)的方法時(shí),Java會(huì)要求程序必要要有調(diào)用該方法的權(quán)限。如果程序確實(shí)需要調(diào)用該對象的私有方法,則可先調(diào)用Method對象的:

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

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

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

3.訪問屬性值

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

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

setXxx(Object obj,Xxx val);將obj對象的該Field設(shè)置成val值,此處的Xxx對應(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)建對象

什么是"clone"?

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

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

1. Clone&Copy

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

2. Shallow Clone&Deep

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

在這里插入圖片描述

這個(gè)時(shí)候我們就需要進(jìn)行deep Clone了,對那些非基本型別的域進(jìn)行特殊的處理,例如本例中的hireDay。我們可以重新定義Clone方法,對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對象,原理可以參考我前面關(guān)于public、protected、private的學(xué)習(xí)筆記。

4. Clone()方法的使用

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

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

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

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

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

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

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

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

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

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

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

我們先看下Person類,要序列化某個(gè)類的對象的話,則該類必要實(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 方法將對象轉(zhuǎn)換為可以寫出到流的數(shù)據(jù)。所以整個(gè)流程是這樣的: ObjectOutputStream 將要序列化的對象轉(zhuǎn)換為某種數(shù)據(jù),然后通過 FileOutputStream 連接某磁盤文件,再對象轉(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對象的序列化與反序列化 
 */  
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è)文件輸出流和對象輸出流;文件輸出流用于將字節(jié)輸出到文件,對象輸出流用于將對象輸出為字節(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、對象的反序列化

我們存儲(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對象的序列化與反序列化 
 */  
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è)文件輸出流和對象輸出流;文件輸出流用于將字節(jié)輸出到文件,對象輸出流用于將對象輸出為字節(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)行反序列化也很簡單,主要用到的流是FileInputstream和ObjectInputstream正好與存儲(chǔ)時(shí)用到的流相對應(yīng)。另外從結(jié)果順序我們可以看到反序列化后得到對象的順序與序列化時(shí)的順序一致。

4、總結(jié)

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

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

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

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

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

5、補(bǔ)充

補(bǔ)充一:上面我們舉得例子很簡單,要保存的成員變量要么是基本類型的要么是String類型的。但有時(shí)成員變量有可能是引用類型的,這是的情況會(huì)復(fù)雜一點(diǎn)。那就是當(dāng)要對某對象進(jìn)行序列化時(shí),該對象中的引用變量所引用的對象也會(huì)被同時(shí)序列化,并且該對象中如果也有引用變量的話則該對象也將被序列化。總結(jié)說來就是在序列化的時(shí)候,對象中的所有引用變量所對應(yīng)的對象將會(huì)被同時(shí)序列化。這意味著,引用變量類型也都要實(shí)現(xiàn)Serializable接口。當(dāng)然其他對象的序列化都是自動(dòng)進(jìn)行的。所以我們只要保證里面的引用類型是都實(shí)現(xiàn)Serializable接口就行了,如果沒有的話,會(huì)在編譯時(shí)拋出異常。如果序列化的對象中包含沒有實(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)用對象的構(gòu)造器,這也好理解,如果調(diào)用了構(gòu)造器的話,對象的狀態(tài)不就又重新初始化了嗎。

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

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

相關(guān)文章

  • hadoop運(yùn)行java程序(jar包)并運(yùn)行時(shí)動(dòng)態(tài)指定參數(shù)

    hadoop運(yùn)行java程序(jar包)并運(yùn)行時(shí)動(dòng)態(tài)指定參數(shù)

    這篇文章主要介紹了hadoop如何運(yùn)行java程序(jar包)并運(yùn)行時(shí)動(dòng)態(tài)指定參數(shù),使用hadoop 運(yùn)行 java jar包,Main函數(shù)一定要加上全限定類名,需要的朋友可以參考下
    2021-06-06
  • Java如何利用return結(jié)束方法調(diào)用

    Java如何利用return結(jié)束方法調(diào)用

    這篇文章主要介紹了Java如何利用return結(jié)束方法調(diào)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • SpringCloud Zuul服務(wù)功能與使用方法解析

    SpringCloud Zuul服務(wù)功能與使用方法解析

    這篇文章主要介紹了SpringCloud Zuul服務(wù)功能與使用方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Guava本地緩存的使用過程

    Guava本地緩存的使用過程

    文章介紹了使用Guava和Redis實(shí)現(xiàn)二級緩存的原因,以及如何通過Guava作為一級緩存,Redis作為二級緩存來減少數(shù)據(jù)庫壓力,提高緩存的可靠性,同時(shí),通過一個(gè)具體示例說明了如何在微服務(wù)場景中使用Guava和Redis進(jìn)行二級緩存,最后,總結(jié)了Guava的參數(shù)機(jī)制
    2025-01-01
  • Spring中@Scope注解用法解析

    Spring中@Scope注解用法解析

    這篇文章主要介紹了Spring中@Scope注解用法解析,@Scope注解主要作用是調(diào)節(jié)Ioc容器中的作用域,在Spring IoC容器中主要有以下五種作用域,需要的朋友可以參考下
    2023-11-11
  • Java如何從json字符串中獲取某個(gè)值詳解

    Java如何從json字符串中獲取某個(gè)值詳解

    Java開發(fā)當(dāng)中經(jīng)常需要Json格式的數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于Java如何從json字符串中獲取某個(gè)值的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • Java中isAssignableFrom的用法詳解

    Java中isAssignableFrom的用法詳解

    下面小編就為大家?guī)硪黄狫ava中isAssignableFrom的用法詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • 詳解Java編程中static關(guān)鍵字和final關(guān)鍵字的使用

    詳解Java編程中static關(guān)鍵字和final關(guān)鍵字的使用

    這篇文章主要介紹了詳解Java編程中static關(guān)鍵字和final關(guān)鍵字的使用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • JAVA獲得域名IP地址的方法

    JAVA獲得域名IP地址的方法

    這篇文章主要介紹了JAVA獲得域名IP地址的方法,涉及java域名操作的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • RestTemplate文件上傳下載與大文件流式下載

    RestTemplate文件上傳下載與大文件流式下載

    這篇文章主要為大家介紹了RestTemplate文件上傳下載與大文件流式下載的使用方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步
    2022-03-03

最新評論

凤庆县| 珠海市| 邓州市| 潞西市| 无为县| 罗甸县| 德阳市| 上蔡县| 澄江县| 文化| 长岭县| 鸡泽县| 治多县| 景谷| 尖扎县| 米泉市| 油尖旺区| 海晏县| 化隆| 东安县| 伊金霍洛旗| 定日县| 鄢陵县| 霍城县| 海盐县| 商洛市| 新沂市| 乌鲁木齐县| 临澧县| 邹城市| 察隅县| 额尔古纳市| 临武县| 昂仁县| 新平| 肇东市| 襄城县| 兴义市| 高雄县| 泰来县| 登封市|