對象的引用傳遞

引用傳遞也稱為傳地址,指的是在方法的調(diào)用時啦辐,傳遞的參數(shù)是按引用傳遞卓嫂,其實(shí)傳遞的是引用地址慷暂,也就是變量所對應(yīng)的內(nèi)存空間的地址。
方法調(diào)用時命黔,若實(shí)際參數(shù)的引用——地址被傳遞給方法中相對應(yīng)的形式參數(shù)呜呐,即形式參數(shù)和實(shí)際參數(shù)擁有相同的存儲單元就斤。在方法執(zhí)行過程當(dāng)中悍募,對形式參數(shù)的操作實(shí)際上就是對實(shí)際參數(shù)的操作,因此形式參數(shù)值的改變將會影響實(shí)際參數(shù)值洋机。

  如果想要進(jìn)行引用傳遞分析坠宴,那么就得首先清楚兩塊內(nèi)存。

1绷旗,堆內(nèi)存:堆內(nèi)存可以理解為一個對象的具體信息喜鼓,每一個對象保存的只是屬性信息,每一塊堆內(nèi)存的開辟都要通過關(guān)鍵字new完成衔肢。
2庄岖,棧內(nèi)存:可以理解為一個整型變量(只能夠保存一個數(shù)的值),其中保存的一塊(只能保存一塊)堆內(nèi)存空間的內(nèi)存地址數(shù)值角骤。但為了方便理解隅忿,可以假設(shè)其保存的是對象的名字。

對象實(shí)例化分配內(nèi)存操作
class Book
{
    String title;
    double price;
    public void talk()
    {
        System.out.println("title:"+this.title);
        System.out.println("price:"+this.price);
    }
}
class hehe
{
    public static void main(String args[])
    {
        Book book=null;   //聲明對象
        book =new Book();    //實(shí)例化一個對象
        book.title="java程序設(shè)計(jì)";  //設(shè)置類中title屬性
        book.price=39.8;  //設(shè)置price屬性
        book.talk();  //此處方法使用對象調(diào)用邦尊,不是直接調(diào)用
    }
}

該程序內(nèi)部執(zhí)行過程圖


圖片發(fā)自簡書App

本程序如果沒有實(shí)例化對象(未開辟堆內(nèi)存空間的對象)進(jìn)行類中的屬性或方法的調(diào)用的時候會出現(xiàn)異常背桐。所以對象在使用之前一定要開辟堆內(nèi)存空間。
在程序中一個關(guān)鍵字new產(chǎn)生一個對象蝉揍,就開辟一個內(nèi)存空間链峭,如果有兩個關(guān)鍵字new,就表示開辟兩個內(nèi)存空間又沾。此處的兩個對象都占有各自的內(nèi)存空間弊仪,彼此的操作應(yīng)該是獨(dú)立的。例:
Book bookA=new Book(); //實(shí)例化一個對象
Book bookB=new Book(); //實(shí)例化一個對象
用關(guān)鍵字new實(shí)例化兩個對象bookA和bookB杖刷,兩個對象各占用一個獨(dú)立的空間撼短,彼此獨(dú)立。因此只要存在了關(guān)鍵字new挺勿,不管何種情況下曲横,都表示要開辟新的內(nèi)存空間。

-----------------------------分割線----------------------------

引用數(shù)據(jù)類型的傳遞
在java中,類本身就是引用數(shù)據(jù)類型禾嫉,而對引用數(shù)據(jù)類型實(shí)際上就相當(dāng)于其他語言的指針概念灾杰。
在Java中對于方法參數(shù)的傳遞,對象是傳遞引用熙参,基本數(shù)據(jù)類型是傳遞值艳吠。

//在函數(shù)中傳遞基本數(shù)據(jù)類型
class hehe
{
    public static void change(int i,int j)  //交換參數(shù)的值
    {
        int temp=i;   //完成兩個變量值的交換
        i=j;
        j=temp;
    }
    public static void main(String args[])
    {
        int a=3;
        int b=4;
        change(a,b);   //調(diào)用方法
        System.out.println("a="+a);
        System.out.println("b="+b);
    }
}

引用數(shù)據(jù)類型的傳遞并沒有改變數(shù)據(jù)本身的值。因此參數(shù)中傳遞的是基本類型a和b的備份孽椰,在函數(shù)中交換的也是那份備份的值而不是數(shù)據(jù)本身昭娩。


傳遞引用數(shù)據(jù)類型

class hehe
{
    public static void change(int[] count)
    {
        count[0]=0;
        System.out.println("在方法內(nèi)部count[0]="+count[0]);
    }
    public static void main(String args[])
    {
        int[] count={1,2,3,4,5};
        System.out.println("方法執(zhí)行前count[0]="+count[0]);
        change(count);    //調(diào)用change方法
        System.out.println("方法執(zhí)行后count[0]="+count[0]);
    }
}

在方法中傳遞引用數(shù)據(jù)類型int數(shù)組,實(shí)際上是其引用count的備份黍匾,他們都指向數(shù)組對象栏渺,在方法中可以數(shù)組對象內(nèi)容。即:對復(fù)制的引用所調(diào)用的方法更改的是同一個對象锐涯。


對象的傳遞引用

class Person
{
    String name;
    int age;
}
class can
{
    public static void main(String args[])
    {
        Person p1=null;  //聲明對象p1磕诊,此值為null,尚未實(shí)例化
        Person p2=null;  //聲明對象p2纹腌,此值為null霎终,尚未實(shí)例化
        p1=new Person();   //實(shí)例化對象p1
        p1.age=25;
        p1.name="kimi";
        p2=p1;   //將p1引用的給p2
        System.out.println("姓名,"+p2.name);
        System.out.println("年齡升薯,"+p2.age);
        p1=null;
    }
}

將p1的引用賦給p2莱褒,相當(dāng)于p1和p2都指向同一塊內(nèi)存。 最后一行代碼將p1對象賦值為null涎劈,表示此對象不在引用任何內(nèi)存空間广凸。程序執(zhí)行完此行以后實(shí)際上p1斷開了對之前實(shí)例化對象的引用,而p2則繼續(xù)指向p1原先的引用责语∨谡希可以理解為p2是通過p1實(shí)例化的,或者p1將自身的引用傳遞給了p2坤候。


圖片發(fā)自簡書App

通過上圖分析可以得出結(jié)論:所謂引用傳遞胁赢,指的是同一塊堆內(nèi)存空間,同時被多個棧內(nèi)存所指向白筹。引用傳遞的核心認(rèn)識:不同的棧內(nèi)存如果如果指向了同一塊堆內(nèi)存之中智末,所做的修改將影響所有的棧內(nèi)存。


引用傳遞的使用

class Book
{
    String title;
    double price;
    public void talk()
    {
        System.out.println("title:"+this.title);
        System.out.println("price:"+this.price);
    }
}
class hehe
{
    
    public static void main(String args[])
    {
        Book bookA=new Book();
        Book bookB=new Book();
        bookA.title="java程序設(shè)計(jì)";
        bookA.price=40;
        System.out.println("引用傳遞前對象bookA:");
        bookA.talk();
        bookB.title="java web開發(fā)";
        bookB.price=60;
        bookB=bookA;   //引用傳遞
        bookB.title="android開發(fā)";
        System.out.println("引用傳遞后對象bookA:");
        bookA.talk();
    }
}

執(zhí)行bookA=bookB引用傳遞之前徒河,bookA,bookB是用兩個new關(guān)鍵字創(chuàng)建對象系馆,有各自獨(dú)立的堆內(nèi)存,屬性各不相同顽照。但執(zhí)行引用傳遞之后由蘑,bookA的引用傳遞給bookB闽寡,bookB不在指向原來的堆內(nèi)存,而是和bookA指向同一塊堆內(nèi)存尼酿,所以對bookB屬性值的設(shè)置就是對bookA相應(yīng)的屬性值修改爷狈,bookA.title(即bookB.title)="android開發(fā)";裳擎。
每一塊棧內(nèi)存只能夠保存一塊堆內(nèi)存地址涎永,但是反過來,一塊堆內(nèi)存可以同時被多個棧內(nèi)存指向鹿响,在這種情況下羡微,如果要改變某一個棧內(nèi)存的保存地址內(nèi)容,則必須先斷開已有的堆內(nèi)存地址連接惶我,才可能指向新的堆內(nèi)存空間妈倔,而如果一塊堆內(nèi)存空間內(nèi)沒有任何棧內(nèi)存所指向的話,那么這塊空間就成為垃圾指孤,所有垃圾將等待被jvm中g(shù)c進(jìn)行不定期收集启涯,同時進(jìn)行內(nèi)存空間釋放贬堵。

對象的引用

class Person
{
    private String no;
    private String name;
    private House house;
    public Person(String no,String name)
    {
        this.no=no;
        this.name=name;
    }
    public String getPersonInfo()
    {
        return "人的編號:"+this.no+"姓名:"+this.name;
    }
    public void setHouse(House house)
    {
        this.house=house;   //引用傳遞
    }
    public House getHouse()
    {
        return this.house;
    }
}
class House
{
    private double area;
    private String address;
    private Person person;
    public House(double area,String adderss)
    {
        this.area=area;
        this.address=adderss;
    }
    public String getHouseInfo()
    {
        return "房子面積:"+this.area+"地址:"+this.address;
    }
    public void setPerson(Person person)
    {
        this.person=person;   //引用傳遞
    }
    public Person getPerson()
    {
        return this.person;
    }
}
class TestHouse
{
    public static void main(String args[])
    {
        Person per=new Person("zs01","張三");
        House ho=new House(88,"王府井百貨");
        per.setHouse(ho);  //人有一間房子
        ho.setPerson(per);  //房子屬于一個人
        System.out.println(per.getPersonInfo());
        System.out.println(per.getHouse().getHouseInfo());
        System.out.println(ho.getPerson().getPersonInfo());
    }
}

對象克隆
對象克隆指的是將一個對象進(jìn)行內(nèi)容的復(fù)制恃轩,如果想實(shí)現(xiàn)克隆操作,可以使用Object類之中定義分一個方法黎做。
protected Object clone() throws CloneNotSupportedException;
如果要想正常地實(shí)現(xiàn)克隆操作叉跛,那么對象所在的類必須實(shí)現(xiàn)Cloneable接口,但這個接口里面沒有定義任何方法蒸殿,此接口屬于標(biāo)識接口筷厘,指的是一種能力的體現(xiàn)。

對象克隆
class Book implements Cloneable
{
    //可以被克隆
    private String title;
    private double price;
    public Book(String title,double price)
    {
        this.title=title;
        this.price=price;
    }
    public void setTitle(String title)
    {
        this.title=title;
    }
    public void setPrice(double price)
    {
        this.price=price;
    }
    public String getTitle()
    {
        return title;
    }
    public double getPrice()
    {
        return price;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException
    {
        //重新定義了一次clone()
        return super.clone();
    }
    @Override
    public String toString()
    {
        return"Book[title"+title+",price="+price+"]";
    }
}
class TestCloneDemo
{
    public static void main(String args[])throws Exception
    {
        Book bookA=new Book("java從入門到精通",79.8);
        Book bookB=(Book) bookA.clone();//對象克隆
        bookB.setPrice(100.8);
        System.out.println(bookA);
        System.out.println(bookB);
    }
}

反射機(jī)制
Java反射機(jī)制是在運(yùn)行狀態(tài)中宏所,對于任意一個類酥艳,都能夠知道這個類的所有屬性和方法;對于任意一個對象爬骤,都能夠調(diào)用他的任意一個方法充石,這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法稱為Java語言的反射機(jī)制。
Java反射機(jī)制主要提供以下功能:在運(yùn)行時判斷任意一個對象所屬的類霞玄;在運(yùn)行時構(gòu)造任意一個類的對象骤铃;在運(yùn)行時判斷任意一個類所具有的成員變量和方法;在運(yùn)行時調(diào)用任意一個對象的方法坷剧。

根據(jù)對象找到類
import java.util.Date;
class hehe
{
    public static void main(String args[])throws Exception
    {
        Date date=new Date();
        Classcls=date.getClass();  //通過Java反射機(jī)制得到類的包名
        System.out.println(cls);
    }
}

getClass()方法是由Object類所定義的:public final Class<?>getClass()惰爬,此方法返回分對象類型為Class,而Class是反射操作的源頭惫企。但是如果要想取得Class類的實(shí)例化對象在Java中有三種方式撕瞧。

方式一:利用Object類的getClass()方法,但是要求必須先產(chǎn)生指定類的對象才可以,幾乎不用

Date date=new Date();
Class<?>cls=date.getClass();
System.out.println(cls);

方式二:利用"類.class"的形式取得Class類的對象丛版,在Hibernate上使用咨跌。

Class<?>cls=java.util.class;
System.out.println(cls);

方式三:利用Class類提供的一個方法完成,在系統(tǒng)構(gòu)架中使用硼婿。

Class<?>cls=Class.forName("java.util.Date");
System.out.println(cls);
根據(jù)對象找到類
class Book
{
    private String title;
    private double price;
    public void setPrice(double price)
    {
        this.price=price;
    }
    public void setTitle(String title)
    {
        this.title=title;
    }
    @Override
    public String toString()
    {
        return"圖書名稱"+this.title+",價格"+this.price;
    }
}
class hehe
{
    public static void main(String args[])throws Exception
    {
        Classcls=Class.forName("Book");
        Book book=(Book)cls.newInstance();  //實(shí)例化一個對象
        book.setTitle("Java開發(fā)實(shí)戰(zhàn)經(jīng)典");
        book.setPrice(79.8);
        System.out.println(book);
    }
}

傳統(tǒng)工廠設(shè)計(jì)模式

*interface Book
{
    public String getTitle();
}
class MathBook implements Book
{
    @Override
    public String getTitle()
    {
        return"數(shù)學(xué)類圖書";
    }
}
class Factory
{
    public static Book getInstance(String className)
    {
        if("mathbook".equals(className))
        {
            return new MathBook();
        }
        return null;
    }
}
class hehe
{
    public static void main(String args[])
    {
        Book book=Factory.getInstance("mathbook");  //實(shí)例化一個對象
        System.out.println(book.getTitle());
    }
}

反射機(jī)制工廠模式

interface Book
{
    public String getTitle();
}
class MathBook implements Book
{
    @Override
    public String getTitle()
    {
        return"數(shù)學(xué)類圖書";
    }
}
class A implements Book
{
    @Override
    public String getTitle()
    {
        return"計(jì)算機(jī)類圖書";
    }
}
class Factory
{
    public static Book getInstance(String className)
    {
        Book book=null;
        try
        {
            book=(Book)Class.forName(className).newInstance();  //利用反射機(jī)制實(shí)例化一個對象
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return book;
    }
}
class heheheh
{
    public static void main(String args[])throws Exception
    {
        Book book=Factory.getInstance("A");
        System.out.println(book.getTitle());
    }
}

反射機(jī)制其他操作
如果類中沒有提供無參構(gòu)造方法锌半,只提供了有參構(gòu)造方法,則就必須明確的調(diào)用指定的構(gòu)造方法才可以通過反射機(jī)制實(shí)例化對象寇漫。取得制定構(gòu)造方法如下:
public Constructor<T>getConstructor(Class<?>…parameterTypes)throws NoSuchMethodException,SecurityException;
在Comstrucoor類中提供有一個實(shí)例化對象方法刊殉。
public T newInstance(Object…initargs)throws

InstantiationException,LLLegalAccessException,

LLLegalArgumentException,IncocationTargetException

調(diào)用構(gòu)造方法取得實(shí)例化對象**
import java.lang.reflect.Constructor;
class Book
{
    private String title;
    private double price;
    public Book(String title,double price)
    {
        this.title=title;
        this.price=price;
    }

    @Override
    public String toString()
    {
        return"圖書名稱"+this.title+",圖書價格"+this.price;
    }
}
class hehe
{
    public static void main(String args[])throws Exception
    {
        Classcls=Class.forName("Book");
        Constructorcons=cls.getConstructor(String.class,double.class);
        Book book=(Book)cons.newInstance("Java開發(fā)實(shí)戰(zhàn)金典",79.8);
        System.out.println(book);
    }
}

針對屬性的操作明確給出要求,利用setter和getter設(shè)置和取得州胳,而對于setter和getter要求必須按照指定格式編寫记焊。之所以存在這樣的要求,是因?yàn)榉瓷錂C(jī)制的原因栓撞。此時可以用Class類中的如下方法取得方法的對象遍膜。

public Method getMethod(String name,Class<?>…parameterTypes)
throws NoSuchMethodException,SecurityException;

取得了Method類的對象后可以利用以下方法進(jìn)行方法的反射調(diào)用。

public Object invoke(Object obj,Object…args)throws LLLegalAccessException,
LLLegalArgumentException,Invocation TargetException;
setter瓤湘,getter的使用
import java.lang.reflect.Method;
class Book
{
    private String title;
    public void setTitle(String title)
    {
        this.title=title;
    }
    public String getTitle()
    {
        return title;
    }
}
class hehe
{
    public static void main(String args[])throws Exception
    {
        String filedName="title";  //u要操作的屬性
        String titleValue="Java開發(fā)實(shí)戰(zhàn)金典";
        Classcls=Class.forName("Book");
        Object obj=cls.newInstance();   //產(chǎn)生對象可分配堆內(nèi)存
        Method setMethod=cls.getMethod("set"+initcap(filedName),String.class);
        Method getMethod=cls.getMethod("get"+initcap(filedName));
        setMethod.invoke(obj,titleValue);  //對象.setTitle()調(diào)用
        System.out.println(getMethod.invoke(obj));   //對象.getTitle()調(diào)用
    }
    public static String initcap(String str)
    {
        return str.substring(0,1).toUpperCase()+str.substring(1);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓢颅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子弛说,更是在濱河造成了極大的恐慌挽懦,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件木人,死亡現(xiàn)場離奇詭異信柿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)醒第,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門渔嚷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人稠曼,你說我怎么就攤上這事形病。” “怎么了蒲列?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵窒朋,是天一觀的道長。 經(jīng)常有香客問我蝗岖,道長侥猩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任抵赢,我火速辦了婚禮欺劳,結(jié)果婚禮上唧取,老公的妹妹穿的比我還像新娘。我一直安慰自己划提,他們只是感情好枫弟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鹏往,像睡著了一般淡诗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伊履,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天韩容,我揣著相機(jī)與錄音,去河邊找鬼唐瀑。 笑死群凶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哄辣。 我是一名探鬼主播请梢,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼力穗!你這毒婦竟也來了毅弧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤睛廊,失蹤者是張志新(化名)和其女友劉穎形真,沒想到半個月后杉编,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體超全,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年邓馒,在試婚紗的時候發(fā)現(xiàn)自己被綠了嘶朱。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡光酣,死狀恐怖疏遏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情救军,我是刑警寧澤财异,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站唱遭,受9級特大地震影響戳寸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拷泽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一疫鹊、第九天 我趴在偏房一處隱蔽的房頂上張望袖瞻。 院中可真熱鬧,春花似錦拆吆、人聲如沸聋迎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽霉晕。三九已至,卻和暖如春捞奕,著一層夾襖步出監(jiān)牢的瞬間娄昆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工缝彬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萌焰,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓谷浅,卻偏偏與公主長得像扒俯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子一疯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在撼玄,面了一些公司,掛了不少墩邀,但最終還是拿到小米掌猛、百度、阿里眉睹、京東荔茬、新浪、CVTE竹海、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,207評論 11 349
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理慕蔚,因此不免有一些不準(zhǔn)確的地方,同時不同JDK版本的...
    高廣超閱讀 15,564評論 3 83
  • Java8張圖 11斋配、字符串不變性 12孔飒、equals()方法、hashCode()方法的區(qū)別 13艰争、...
    Miley_MOJIE閱讀 3,696評論 0 11
  • 前言 很早前就想聊聊 MVC坏瞄、MVVM,因?yàn)檫@是個非常有意思的話題甩卓,而且近些年來新的架構(gòu)設(shè)計(jì)模式也層出不窮鸠匀,除卻 ...
    KavinZhou閱讀 670評論 0 6
  • 看曹操南征北戰(zhàn),從中年戰(zhàn)斗到老年猛频,始終沒有戰(zhàn)勝蜀國狮崩,但是給自己的兒子打下穩(wěn)固的江山蛛勉,最后曹丕卻統(tǒng)一了蜀國。司馬懿沒...
    一只羊1237閱讀 307評論 0 0