VB.NET 結構(Structure)和類(Class)的區別


類是我們用來構造 VB.NET 應用程序時的最基本的編程結構了。

那結構與類有什么相似之處與不同之處呢?

結構和類,

相同之處是都含有成員,包括構造函數、方法、屬性、字段、常量、枚舉和事件,都可以實現接口,都有共享的構造函數,都能對成員進行封裝。

沒錯都有構造函數,那結構的構造函數是什么,結構難道也可被實例化成對象?

看這一段代碼:

Module Module1
    Private Structure structureA
        Dim Name As String
        Dim Age As Integer

        Public Sub New(ByVal _Name As String, ByVal _Age As Integer)
            Name = _Name
            Age = _Age
        End Sub
    End Structure

    Sub Main()
        Dim intA As New structureA  '無參數的構造函數
        Dim intB As New structureA("小明", 17) '有參數的構造函數
    End Sub
End Module

怎么樣,是不是很好奇,明明只定義一個帶參數的構造函數,intB 的實例化我們可以明白,但是是 intA 怎么也能通過編譯器檢測,給實例化呢?

是不是很好奇,結構怎么也能實例化成對象,和類很象呢!

原因是,每個結構都隱式地具有 Public 無參數實例構造函數也就是 Public Sub New(),該構造函數能產生結構的默認值。所以你平時不寫構造函數,也一樣可以 New出一個結構來。

事實上,我們在結構類型聲明中不能聲明無參數的構造函數,只能聲明“帶參數”的構造函數。都可以用 new 來實例化。

那結構和類在內存分配上難道也是 一樣的嗎?當然不一樣,差別可就大了。

簡單來說 ,結構是值類型,而類是引用類型。因此,結構使用堆棧分配,類使用堆(托管堆)分配。

示例:

Module Module1
    Private Structure structureA
        Dim Name As String
        Dim Age As Integer
        Public Sub New(ByVal _Name As String, ByVal _Age As Integer)
            Name = _Name
            Age = _Age
        End Sub
    End Structure

    Private Class classA
        Public sdNumber As Integer = 0
    End Class

    Sub Main()
        Dim stcA As New structureA("小明", 0) '有參數的構造函數
        Dim stcB As structureA = stcA
        stcB.Age = 17
        Dim clsA As New classA
        Dim clsB As classA = clsA
        clsB.sdNumber = 1001
        Console.WriteLine("stcA.Age = {0} ,stcB.Age = {1} ", stcA.Age, stcB.Age)
        Console.WriteLine("clsA .sdNumber = {0} ,clsB .sdNumber = {1}", clsA.sdNumber, clsB.sdNumber)
        Console.Read()
    End Sub
End Module

結果如圖:

這就是值類型和引用類型的差別。

結構的實例 stcB.Age 賦值並不影響stcA.Age, 這是因為雖然它們同屬於一種SHenry結構,而結構也是屬於值類型的,值類型的變量存儲在堆棧上的,每個變量都有自己單獨的內存空間,所以互不影響。

相反,給 clsB.sdNumber 賦值 17 后; 則會影響slcA.sdNumber 變量的值,這是因為在 Classs 類中,雖然 sdNumber 變量是值類型,但它的對象是類,類是引用類型,而引用類型是存儲在堆(托管堆)上,堆上存儲的是對象的實際對象值。

不管后面定義多少個 class 類型的變量,只要不實例化,它們都只是在堆棧上划分各自的空間,來存儲 class 對象的引用地址,而這每個不同名稱的引用地址都指向同一個引用對象的實際值。所以,不管哪個 class 類型變量改變了值,它都會影響原始值。

說得更清楚一點,類作為引用類型,是存儲在堆上,只能通過引用地址來訪問它們,不能直接訪問。

引用類型的變量總是包含該類型的值引用,或包含空引用。空引用不引用任何內容;除分配空引用外,對空引用進行的任何操作都是無效的。

引用類型的變量賦值只會創建引用的一個副本,而不是所引用的值的副本。它們實際上都是會指向同一塊存儲區的。

結構是直接存儲在堆棧上,要么在數組中,要么在另一個類型中 。當包含結構實例的位置被銷毀時,結構實例也會被銷毀。值類型總是可以直接 訪問。我們不能創建對值類型的引用,也不能引用已銷毀的值類型實例。值類型的變量總是包含此類型的值。與引用類型不同,值類型的值不能為空引用,也不能引用派生相近程度較大的類型的對象。值類型的變量賦值會創建所賦的值的副 本,當然會新開辟一塊內存區來保存值。

那它們還有什么區別沒有呢?

當然有很多,比如所有的結構成員都默認為 Public,而類的變量和常量默認為 Private。其他的類成員默認為 Public;結構成員不能聲明為 Protected,而類成員可以;結構過程不能處理事件,類過程可以;結構變量聲明不能指定初始值、New 關鍵字或數組初始大小,類變量聲明可以。

結構從不終止,所以公共語言運行庫從不在任何結構上調用 Finalize 方法;類可由垃圾回收器終止,垃圾回收器會跟蹤未完成的引用直到某個特定的實例,當檢測到沒有剩下的活動引用時, 垃圾回收器將在類上調用 Finalize。”

因為結構是值類型,是由系統統一管理內存,不是引用,所以不會對內存造成危害。

還有結構是不可繼承的,而類可以繼承。其實結構自身是從 ValueType 類隱式繼承下來的。

數據類型可分為值類型和引用類型。值類型要么是堆棧分配的,要么是在結構中以內聯方式分配的。引用類型是堆分配的,引用類型和值類型都是從最終的基類 Object 派生出來的。當值類型需要充當對象時 ,就在堆上分配一個包裝,該包裝能使值類型看上去像引用對象一樣,並且將該值類型的值復制給它。該包裝被加上標記,以便系統知道它包含一個值類型。這個過程程稱為裝箱,其反向過程程稱為拆箱。裝箱和拆箱能夠使任何類型像對象一樣進行處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM