Це важливий момент, але ІМХО варто розуміти.
Усі мови OO завжди роблять копії посилань і ніколи не копіюють об'єкт "невидимим". Це було б багато важче писати програми , якщо мови OO працювали інакше. Наприклад, функції та методи ніколи не могли оновити об’єкт. Ява та більшість мов OO майже неможливо було б використовувати без значної додаткової складності.
Об'єкт у програмі повинен мати певне значення. Наприклад, це репрезентує щось конкретне в реальному фізичному світі. Зазвичай має сенс мати багато посилань на одне і те ж. Наприклад, мою домашню адресу можна надати багатьом людям та організаціям, і ця адреса завжди посилається на одне фізичне місце розташування. Отже, перший пункт полягає в тому, що об'єкти часто представляють щось конкретне, реальне або конкретне; і тому можливість мати багато посилань на одне і те ж є надзвичайно корисним. Інакше було б важче написати програми.
Кожен раз, коли ви передаєте a
як аргумент / параметр іншій функції, наприклад, виклику
foo(Dog aDoggy);
або застосуванню методу до a
, базовий програмний код робить копію посилання, щоб створити другу посилання на той самий об'єкт.
Далі, якщо код з скопійованим посиланням знаходиться в іншому потоці, то обидва можуть бути використані одночасно для доступу до одного і того ж об'єкта.
Тож у більшості корисних програм буде кілька посилань на один і той же об’єкт, оскільки це семантика більшості мов програмування OO.
Тепер, якщо ми подумаємо про це, оскільки передача посилань є єдиним механізмом, доступним у багатьох мовах ОО (C ++ підтримує обидва), ми можемо очікувати, що це буде "правильне" поведінка за замовчуванням .
IMHO з використанням посилань є правильним за замовчуванням з кількох причин:
- Це гарантує, що значення об'єкта, який використовується у двох різних місцях, однакове. Уявіть, як розміщуєте об’єкт у двох різних структурах даних (масиви, списки тощо) та виконуєте деякі операції над об'єктом, який його змінює. Це може бути кошмаром для налагодження. Що ще важливіше, це один і той же об’єкт в обох структурах даних, або програма має помилку.
- Ви можете радісно рефакторний код на кілька функцій або об'єднати код з кількох функцій в одну, і семантика не змінюється. Якби мова не передбачала еталонної семантики, було б ще складніше змінити код.
Існує також аргумент ефективності; робити копії цілих об'єктів менш ефективно, ніж копіювати посилання. Однак я думаю, що це не вдається. Кілька посилань на один і той же об'єкт мають більше сенсу і простіші у використанні, оскільки вони відповідають семантиці реального фізичного світу.
Отже, IMHO, зазвичай має сенс мати кілька посилань на один і той же об’єкт. У незвичайних випадках, коли це не має сенсу в контексті алгоритму, більшість мов надають можливість зробити «клон» або глибоку копію. Однак це не за замовчуванням.
Я думаю, що люди, які стверджують, що це не повинно бути за замовчуванням, використовують мову, яка не забезпечує автоматичне вивезення сміття. Наприклад, старомодний C ++. Проблема полягає в тому, що їм потрібно знайти спосіб збирати "мертві" об'єкти, а не відновлювати об'єкти, які все ще можуть знадобитися; наявність кількох посилань на один і той же об’єкт робить це важко.
Я думаю, якщо C ++ мав достатньо недорогий збір сміття, так що всі об'єкти, на які посилаються, збирають сміття, значна частина заперечень відпадає. Ще будуть випадки, коли референтна семантика - це не те, що потрібно. Однак, на моєму досвіді, люди, які можуть ідентифікувати ці ситуації, також, як правило, здатні вибрати відповідну семантику.
Я вважаю, що є певні докази того, що велика кількість коду в програмі C ++ є для обробки або зменшення збору сміття. Однак написання та підтримка такого роду "інфраструктурного" коду додає витрат; саме там можна зробити мову простішою у використанні чи надійнішою. Так, наприклад, мова Go розроблена з акцентом на усунення деяких недоліків C ++, і у неї немає іншого вибору, крім збирання сміття.
Це, звичайно, не має значення в контексті Java. Він також був розроблений, щоб бути простим у використанні, а також збирання сміття. Отже, наявність декількох посилань є семантикою за замовчуванням і є відносно безпечною в тому сенсі, що об'єкти не відновлюються, поки є посилання на них. Звичайно, їх може утримувати структура даних, тому що програма не є належним чином приведена в дію, коли вона дійсно закінчилася об'єктом.
Отже, обертаючись навколо вашого запитання (з невеликим узагальненням), коли ви хочете більше, ніж одне посилання на один і той же об’єкт? Дуже багато в кожній ситуації, про яку я можу придумати. Вони є семантикою за замовчуванням для більшості мов механізму передачі параметрів. Я припускаю, що це тому, що семантика поводження з об'єктами, що існує в реальному світі, за замовчуванням в значній мірі повинна бути посиланням (адже фактичні об'єкти там є).
Будь-яку іншу семантику було б важче обробити.
Dog a = new Dog("rover"); // initialise with name
DogList dl = new DogList()
dl.add(a)
...
a.setOwner("Mr Been")
Я припускаю, що "ровер" dl
повинен бути таким, який здійснюється за допомогою setOwner
програм або важко написати, зрозуміти, налагодити чи змінити. Я думаю, що більшість програмістів будуть інакше спантеличені або збентежені.
пізніше собаку продають:
soldDog = dl.lookupOwner("rover", "Mr Been")
soldDog.setOwner("Mr Mcgoo")
Цей вид обробки є звичайним і нормальним. Тож довідкова семантика є типовою, оскільки вона зазвичай має найбільше значення.
Підсумок: Завжди має сенс мати кілька посилань на один і той же об'єкт.