Найти тему
Programmer

Основы программирования. Как научиться различать ссылки-коробки от самих объектов?

Оглавление

Казалось бы, простейшая информация, но о ней вам не говорят никто в мире, ни официальщина, ни повторяющие ее безмозгло ваши учителя и авторы учебников и блогеры. Но давайте разберемся с темой ссылок и объектов в них, так как с этими операциями вы встречаетесь везде в программировании (и реальной жизни) каждую секунду.

Ссылки и указатели - это коробки от объектов

Итак, в прошлых статьях я вам уже пояснял простую вещь (которую никто не говорит), что ссылки и указатели в программировании являются просто коробками от объектов. Все просто! Это два похожих друг на друга разных типов данных, где ссылка является "безопасной" коробкой и везде применяется в Java и C# для любого обращения к ссылочным (коробочным) объектам типа class.

Объект самой коробки по типу отличается от объекта внутри
Объект самой коробки по типу отличается от объекта внутри

Структуры C# и "оберточные" примитивные типы Java (вы их не можете создавать в Java) являются "кастрированными" безкоробочными объектами, которые находятся в малой сверхбыстрой вечной памяти или в "стеке". Они могут быть и в глобальной памяти (в куче), если завернуты в обертку класса или в ссылку.

Указатели являются "небезопасными" коробками объектов, которые могут принимать значения любых адресов и пространств без разрешения операционной системы просто по номеру ячеек памяти. В языках C++ и C# указатели можно использовать почти везде, но в C# не рекомендуется этого делать и везде поставлены препоны для этого. Подробно указатели и ссылки буду разбирать для вас в отдельных статьях.

В чем путаница при работе со ссылками?

В Java , C# и даже C++ постоянно происходит путаница у людей при работе со ссылками, так как официальщина в документации сводит с толку разум. Вот давайте возьмем простой пример создания ссылочного объекта в Java и C# и я поясню на нем путаницу.

string file = "vasja.txt";

System.IO.StreamWriter wr = new System.IO.StreamWriter (file);

В данном примере из C# из стандартной библиотеки .NET мы видим в двух строках создание строковой переменной файла и затем создание ссылочного объекта с запихиванием его в коробку-ссылку, причем в конструкторе объекта в скобках ему передается созданное имя файла в ссылочной переменной с именем file типа string.

Строковая переменная с именем file также является коробкой-ссылкой типа string от коробочного объекта (class) неизменяемой строки. Коренное отличие коробок-ссылок от указателей в том, что ссылки внешне принимают значение объекта, содержащегося в данной коробке! Указатели принимают значения адресов объектов, но "под капотом" и ссылки и указатели хранят именно адреса объектов и позже я вам это поясню, в чем разница внешних и внутренних значений объектов.

То есть две коробки (ссылка и указатель), но ссылка принимает внешнее значение своего текущего объекта, а указатель принимает значение текущего адреса своего объекта в памяти. Во второй строке примера переменная-ссылка wr типа System.IO.StreamWriter создается с нуля и сразу при создании ей присваивается значение объекта в коробке оператором new с передачей в конструкторе параметра file. Но что делает оператор new ? Это важный вопрос, о котором молчат...

Оператор new во второй строке примера "под капотом" создает мгновенную безымянную коробку-ссылку на безымянный объект типа System.IO.StreamWriter и после этого мгновенная коробка копируется оператором "=" влево в постоянную коробку wr такого же типа.

Ранее я не понимал, что справа от "=" находится не просто объект для ссылки в виде оператора new, а значение ссылки в виде объекта, но типом объекта справа от "=" является "ссылка", ведь я вас учил, что в шлюзовых операциях тип на входе и выходе одинаковый!

Выше сказанное означает, что при полностью внешне одинаковой записи объектов их тип может быть разный, в одном случае объект означает самого себя и свой тип, в другом такая же запись объекта означает переменную или объект типа ссылки-коробки на внутренний объект. В этом получается путаница.

int object1 = new int (6);

System.Random object2 = new System.Random (10) ;

Вот в этих примерах из языков C# и Java вы наглядно можете видеть, как внешне одинаковые объекты могут означать абсолютно разные вещи. В первом случае "под капотом" целая переменная object1 копирует значение объекта справа, который является мгновенным объектом целого типа (но компилятор не будет в реале копировать примитивные объекты, в будущем поясню).

Во второй строке уже оператор new создает мгновенную безымянную коробку на безымянный объект типа System.Random, то есть объект справа является типом ссылки, так как объект слева является типом ссылки (class System.Random), а в шлюзовых операциях объект слева определяет тип всей операции. То есть если вы напишете число 7 , то это будет мгновенным объектом типа struct System.Int32 (int), а если вы напишете Random obj или new Random (5) , то это будет в обоих случаях создание коробок класса (class) Random , только в первом случае вы объявляете постоянную ссылку-коробку obj, а во втором создаете мгновенную коробку без имени на только что созданный безымянный объект оператором new "под капотом". Теперь понятно?

Вот именно в этом вся путаница при записи ссылок-коробок и объектов, так как коробки принимают значения объектов в них, хотя в Java и C# специально сделали структуры и примитивные "оберточные" типы безкоробочными объектами, чтобы путаницу сделать меньше, но в языке C++ вы сам объект и ссылку на него можете вообще внешне не отличить, а сделать это можно будет только в контексте данной строки кода.

В общем, старайтесь никогда не путать в коде запись объекта и коробки-ссылки от него, так как это разные типы данных, которые внешне записываются одинаково. В будущем покажу вам, как объекты разных типов принимают абсолютно одинаковые внешние значения, которые "под капотом" абсолютно разные. Подписывайтесь и ставьте лайки, пока...