Итак, в прошлых темах мы рассмотрели различные типы данных - как примитивные типы Integer, Double и др., так и комплексные типы - классы и структуры. Все типы данных в Visual Basic.NET можно разделить на две группы: типы значений или значимые типы (value types) и ссылочные типы (reference types). И при создании программ очень важно понимать между ними различия для корректной работы приложения.
Типы значений представлены следующими типами данных:
Целочисленные типы (Byte, SByte, Char, Short, UShort, Integer, UInteger, Long, ULong)
Типы с плавающей запятой (Single, Double)
Тип Decimal
Тип Boolean
Перечисления Enum
Структуры
Ссылочные типы:
Тип Object
Тип String
Классы
Интерфейсы
Делегаты
Различия между этими типами данных основываются на разном подходе к организации их в памяти. Вся память в .NET делится на два типа: стек и куча (heap). Типы значений являются производными от типа System.ValueType и размещают свое значение в стеке. Стек представляет собой структуру данных, которая растет снизу вверх: каждый новый добавляемый элемент помещаются поверх предыдущего. Время жизни переменных таких типов ограничено их контекстом. Физически стек - это некоторая область памяти в адресном пространстве.
При запуске программы в конце блока памяти, зарезервированного для стека, устанавливается указатель стека. При помещении данных в стек, указатель переустанавливается таким образом, что снова указывает на новое свободное место.
Например:
Sub SomeMethod (t As Integer)
Dim x As Integer = 5
Dim y As Integer = 6
Dim z As Integer = x * y * t
End Sub
При вызове этого метода в стек будут помещаться переменные t, x, y и z. Все эти переменные определены в контексте метода SomeMethod. Вне его они не существуют. И после завершения работы метода они уничтожаются, а память очищается.
В отличие от типов значений ссылочные типы хранятся в куче или хипе, которую можно представить как неупорядоченный набор разнородных объектов. Физически это остальная часть памяти, которая доступна процессу программы.
При создании объекта ссылочного типа в стеке помещается ссылка на адрес в куче (хипе). Когда объект ссылочного типа перестает использоваться, то ссылка из стека удаляется. После этого в дело вступает автоматический сборщик мусора (garbage collector): он видит, что на объект в хипе нету больше ссылок, и удаляет этот объект и очищает память.
Чтобы проследить разницу между этими двумя группами типов данных, рассмотрим небольшой пример, в котором будут использоваться сразу и тип значений в виде структуры и ссылочный тип в виде класса.
Sub Test()
Dim state1 As State = New State() 'State - структура, ее данные размещены в стеке
Dim country1 As Country = New Country() 'Country - класс, в стек помещается ссылка на адрес в хипе
'а в хипе располагаются все данные объекта country1
End Sub
Class Country
Public x As Integer
Public y As Integer
End Class
Structure State
Public x As Integer
Public y As Integer
End Structure
Метод Test создает два объекта - структуру и объект класса. Программа выделяет в стеке память для объекта state1. Также в стеке создается
ссылка для объекта country1 (Country country1), а с помощью конструктора выделяется место в хипе (new Country()).
В итоге в стеке будут храниться все поля структуры state1 и адрес на все поля объекта country1 в хипе.
При работе ссылочными данными мы можем столкнуться с проблемой: если при присвоении данных объекту значимого типа он получает копию данных, то при присвоении данных объекту ссылочного типа происходит присвоение не копии объекта, а его адреса. Например:
Sub Test()
Dim state1 As New State()
Dim state2 As New State()
state2.x = 1
state2.y = 2
state1 = state2
state2.x = 5 'state1.x=1 по-прежнему
Dim country1 As New Country()
Dim country2 As New Country()
country2.x = 1
country2.y = 4
country1 = country2
country2.x = 7 ' теперь и country1.x = 7, так как обе ссылки и country1 и country2
'указывают на один объект в хипе
End Sub
Так как state1 - структура, то при присвоении state1 = state2 она получает копию структуры state2. А объект класса country1
при присвоении country1 = country2; получает адрес ссылки на тот же объект, на который указывает country2. Поэтому с изменением
country2, так же будет меняться и country1.
Рассмотрим более сложный пример, когда внутри структуры может храниться объект ссылочного типа, например, какого-нибудь класса:
Sub Test()
Dim state1 As New State()
Dim state2 As New State()
state2.country = New Country()
state2.x = 2
state2.country.x = 5
state1 = state2
state2.country.x = 8 ' теперь и state1.country.x=8, так как state1.country и state2.country
' указывают на один объект в хипе
End Sub
Class Country
Public x As Integer
Public y As Integer
End Class
Structure State
Public x As Integer
Public y As Integer
Public country As Country
End Structure
Объекты ссылочных типов данных, хранящиеся в структурах, также размещают в стеке адрес ссылки на объект в хипе. Поэтому при присвоении
двух структур state1 = state2; структура state1 также получит ссылку на объект country в хипе. Поэтому изменение state2.country
повлечет за собой также изменение state1.country.