操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    歡迎加入伯樂在線 專欄作者。

    起因

    之前一直寫C#,因為有GC,所以不用關心對象的復制問題,默認的淺復制就夠了,也就沒去深究、class、值、引用間的區別,前段時間寫了點C++,C++需要手動管理內存,如果類包含有指針或引用成員時就要遵循rule of three,實現復制、賦值復制和析構以正確管理資源,這種生命周期管理函數寫多了感覺挺枯燥的,而且我發現許多 沒有必要實現復制,因為大多數 并不適合用值語義來表達,首先它們本質不是一種“值”,并且我希望傳遞時傳遞同一個對象,而不是一個副本。

    C#中同時保留了值類型和引用類型,而我幾乎從未寫過自定義的值類型。于是我就開始思考值對象和引用對象到底有什么區別,隨即寫下此文分享本人的見解。

    值對象(value )

    什么是值對象

    值對象是標識取決于狀態的對象

    你現在拿出一張紙幣,它就是典型的值對象,雖然每張紙幣都有一個唯一的編號,但實際使用中這個編號是沒有意義的,我們關心的是它們的面值。

    這里紙幣的編號就對應值對象的標識(比如內存地址),紙幣的面值就對應值對象表示的值。

    其它值對象的例子:IP地址、RGB顏色、GUID、地理坐標、日期時間。

    我的理解:值對象是用來表達一個信息的對象,它的狀態是靜態的,且比較“透明”;我們使用值對象時, 關心的是它所表達的信息,而不是這個對象本身

    值對象與不可變性()

    值對象應該被設計成不可變的(),因為

    從理論上講值對象存在的意義就在于表示一個值,它的狀態決定了它的標識,如果狀態修改了,那就是一個新的值,新的對象。簡化編程、避免bug

    如果值對象可變,當它被共享時,一處修改可能會影響另一處引用源對象需要標注嗎,修改操作就會產生“副作用(side )”,如java中的java.util.Date就是可變的引用類型,使用不當就會產生問題://表示一個定時任務 class Task { //設置執行時間 Date (Date date){ this. = date; } //獲取執行時間 Date (){ this.; } //FIXME: 改成 this..clone(); 相當于“手動實現值語義” //延遲執行時間 void delay(int ) { this..(.() + ); } Date ;//執行時間 } task1.(new Date("2016/01/01"); task2.(task1.()); task2.delay(5); //這里本想修改task2的日期,但無意中影響到了task1

    這里的問題在于我們 關心的其實只是一個“日期值”而不是一個java.util.Date對象,所以在傳遞時應該是傳遞表示的日期值,而不是直接傳遞java.util.Date對象。注釋中的FIXME標注是一種解決辦法。

    值對象必須要實現為不可變嗎?

    但是如果把一個類實現為不可變的話,意味著修改一個成員就要創建一個新的對象,如果成員非常多的話,代碼寫起來會比較繁瑣。

    有些語言支持 值語義(value ),對象傳遞時是 傳遞的它所表示的值(傳值),而不是 傳遞對象本身(傳引用),這就意味著傳遞過程就是“復制”,比如C++默認就是值語義、C#中的等,因為是復制,所以值對象不會被共享,也就沒有了上面提到的那個問題,這種情況下,值對象可變的話也是完全可以的,但是值對象仍可能會被“按引用”傳遞,所以把值對象實現為不可變是最保險的手段。

    值對象的實現

    C++

    C++默認就是值語義,如果類狀態較簡單,則可以不做任何特殊處理。如果比較復雜,比如成員包含指針或引用,則就要實現生命周期管理函數C# 如果類狀態較簡單,可直接用,因為正好就是值語義

    如果狀態較復雜則用class,類的設計者應該從接口上把它設計成不可變,如果沒有這樣設計,則使用者最好在使用時“手動實現值語義”(見上java.util.Date示例)。

    java

    同C#中的class

    與值對象相關的概念

    與class

    不管是C++和C#中的關鍵字,還是ruby中的::new都是趨向用于定義 簡單的復合類型,所以適合用來定義沒有復雜行為和狀態的值對象。而class更趨向用于定義具有豐富邏輯、復雜狀態的對象類型,、class和值對象、引用對象并不是一一對應的關系,但一般而言,值對象都不會太復雜。

    字符串

    拋開具體的實現,字符串是一個靜態的字符序列,它的狀態決定了它的相等性,是一種值。

    問題1,為什么在C#、java中字符串都是引用類型呢?

    “引用類型”是具體語言/平臺實現中的概念,“值對象”,“引用對象”是語言無關的, 引用類型的對象也可能是值對象,只是引用類型的對象不具有原生的值語義。

    將字符串實現為”引用類型“更多是出于性能考慮。

    避免復制。傳引用,可以避免發生內容的拷貝。可以實現 (字符串扣留)。扣留操作會檢查一個全局字符串扣留池,看有沒有與給定字符串內容相同的已被扣留的字符串對象,如果有則返回,沒有則進行扣留。如果程序中有很多內容相同的字符串對象,這樣能節約內存,這也是模式的一個案例。

    java示例: str1 = " "; // 會被自動”扣留“ str2 = new (str1); // 這時產生了兩個內容相同的對象 .out.(str1 == str2); // 輸出false str2 = str2.(); // 這時 str1 和 str2 指向的是同一個對象 .out.(str1 == str2); // 輸出true

    C#示例:

    var str1 = " "; var str2 = new (str1.()); .(.(str1, str2)); // false str2 = .(str2); .(.(str1, str2)); // true

    問題2,為什么C++中的std::和Ruby中的都是可變的?

    很簡單,這樣用起來更方便。對于C++,可以用const實現不可變性,而Ruby是通過來表示唯一的、不可變的字符串。

    C#中的值類型

    C#語言中的類型分為兩類“值類型”和“引用類型”,strut和enum屬值類型,class屬引用類型。C#編譯器處理時讓該類型繼承了.這個抽象類,而enum則繼承自.Enum,.Enum還是繼承自.。

    值類型 和 引用類型的區別只有一個:一個是值語義(傳值,復制),一個是引用語義(傳引用),至于什么“一個分配于棧,一個分配于堆”,這是具體實現的問題,而且 值類型不一定分配于棧,比如作為引用類型的成員(被捕捉到閉包中同屬該情況)。

    引用對象( )

    引用對象是相等性取決于它的標識的一種對象。

    為什么“相等性取決于標識”?因為在使用引用對象時,我們 關心的是這個對象本身引用源對象需要標注嗎,在傳遞過程中,需要傳遞同一個對象,所以需要傳遞對象的“引用(即標識、一般是內存地址)”,這也就是“ 引用語義( )”。

    我們實際寫程序中,使用對象的目的在于映射問題域中的事物,基本關心的是對象本身,所以對象大多都屬于引用對象。

    實現

    在C#和java中用class定義的類型叫“引用類型”,具有引用語義,創建的對象天生就是引用對象在C/C++中通常通過分配堆內存和傳遞指針實現

    參考

    :////-value-

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有