Итак, в прошлых темах мы рассмотрели различные типы данных - как примитивные типы 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.