Чим посилання на Java відрізняється від вказівника С?


97

C має вказівники, а у Java є те, що називається посиланням. У них є щось спільне в тому сенсі, що всі вони на щось вказують. Я знаю, що вказівники на C зберігають адреси, на які вони вказують. Чи посилання також зберігає адресу? Чим вони відрізняються, за винятком того, що вказівник є більш гнучким та схильним до помилок?


10
Примітка C ++ також має посилання, які відрізняються від покажчиків або посилань на Java
jk.

@jk. Я думав, що це буде так само, як у Java. Яка різниця?
Gnijuohz

17
Посилання на C ++ не є повторномобільними (тобто ви не можете змінити призначений об'єкт) і не зведені до нуля (тобто ви не можете їх посилати взагалі жодним об'єктом).
AProgrammer

@Gnijuohz Перефразовуючи те, що сказав @AProgrammer: finalПосилання на Java майже еквівалентна посиланню на C ++. Причиною того, що вони не є абсолютно еквівалентними, є те, що посилання C ++ додатково не зводиться до нуля, тоді як finalпосилання на Java є нульовим.
Утку

Відповіді:


142

Посилання можуть бути реалізовані, зберігаючи адресу. Зазвичай посилання на Java будуть реалізовуватися як покажчики, але це не вимагається специфікацією. Вони можуть використовувати додатковий шар непрямості для полегшення збору сміття. Зрештою, він (майже завжди) зводиться до покажчиків (у стилі С), які беруть участь у впровадженні посилань (у стилі Java).

Ви не можете робити арифметику вказівника з посиланнями. Найважливіша відмінність між вказівником на C і посиланням на Java полягає в тому, що ви фактично не можете дістати (і маніпулювати) базовим значенням посилання на Java. Іншими словами: ви не можете робити арифметику вказівника.

В C ви можете додати щось до вказівника (тобто адреси) або субстратувати щось, щоб вказати на речі, які знаходяться "поблизу" або вказати на місця, які є в будь-якому місці.

У Java посилання вказує лише на одне і на це. Ви можете зробити змінну утримувати іншу посилання, але ви не можете просто попросити її вказати на "річ після оригінальної речі".

Список літератури сильно набраний. Ще одна відмінність полягає в тому, що тип посилання набагато суворіше керується на Java, ніж тип вказівника знаходиться в C. У C ви можете мати int*та передавати його на a char*та просто повторно інтерпретувати пам'ять у цьому місці. Ця повторна інтерпретація не працює в Java: ви можете інтерпретувати об'єкт лише на іншому кінці посилання як те, що воно вже є (тобто ви можете Objectподавати Stringпосилання лише для того, якщо об’єкт, на який вказували, насправді є String).

Ці відмінності роблять покажчики С більш потужними, але й більш небезпечними. Обидві ці можливості (арифметична вказівка ​​та повторна інтерпретація значень, на які вказують) додають гнучкості до C і є джерелом певної сили мови. Але вони також є великими джерелами проблем, тому що при неправильному використанні вони можуть легко порушити припущення, що ваш код побудований навколо. І використовувати їх досить просто неправильно.


18
+1 для може . Не покладайтеся на деталі впровадження.
CVn

2
+1 Чи не заслуговує сміття як специфічний сміливий момент? Це ще один спосіб, що покажчики С є більш потужними, але й більш небезпечними (ризик зависати вказівниками до звільненої пам’яті, що спричинить пошкодження пам’яті, ризик витоку пам’яті)
MarkJ

Ще одна відмінність між посиланнями та покажчиками полягає в тому, що вказівник на C може бути перетворений у послідовність чисел (наприклад, за допомогою memcpyпереміщення однієї в а char[]) та навпаки. Якщо вказівник перетворений на послідовність чисел, яка зберігається десь (можливо, показана на екрані та скопійована оператором на прокладині паперу), всі копії вказівника всередині комп'ютера знищуються, і ця послідовність чисел перетворюється назад до вказівника (можливо після введення оператором), він все одно повинен вказувати на те саме, що було раніше. Програма, яка ...
supercat

... відображення покажчика як числа, а потім перетворення введених вручну чисел у покажчик може бути "злим", але воно не викликало б невідомого поведінки, якщо оператор не вводить цифри, які не показали, що утворюють дійсні покажчик. Таким чином, збирання сміття загального призначення неможливо у повністю портативному C, оскільки комп'ютер не може знати, чи може існувати копія вказівника десь у Всесвіті.
supercat

Згідно з пунктом 4.3.3 JLS, посилання на Java є вказівниками, тому "Зазвичай посилання Java будуть реалізовуватися як покажчики, але це не вимагається специфікацією". неправдиво.
Lew Bloch

8

Посилання на C ++ знову відрізняються.

Вони повинні бути ініціалізовані і не можуть бути нульовими (принаймні, не у добре сформованій програмі) і не можуть бути повторно використані для посилання на щось інше. посилання на C ++ набагато більше нагадує псевдонім для об'єкта.

Ще одна важлива відмінність між вказівниками та посиланнями Java / C ++ полягає в тому, що ви можете взяти адресу вказівника, ви не можете отримати доступ до адреси посилання (дійсно, посилання на C ++ взагалі не потрібно взагалі існувати як об'єкт в пам'яті), отже, ви можете мати покажчик на покажчик, але не посилання на посилання


4

Посилання Java та покажчики С відрізняються рівно в двох пунктах:

  1. Для першої немає вказівки-арифметики.
  2. І ви не можете створити посилання Java на все, що завгодно, ви можете скопіювати лише збережені десь доступні (статичні поля, поля об’єктів, локальні змінні) або повернуті функціями-викликами (наприклад, виклики конструктора), які таким чином усі відносяться до Java об'єкти (ніколи до основних типів , таких як посилання, char, intі так далі).

Хто - то писав , що посилання є строго типізований, тому що ви не можете змусити компілятор трактувати int*як char*.
Зовсім осторонь того, що саме ця конверсія насправді є безпечною , у С немає поліморфізму, тому порівняння не є початковим.
Безумовно, Java сильніше набрана, ніж C, не те, що це особливість покажчиків C проти посилань на Java, вам потрібно використовувати JNI, щоб порушити безпеку типу (окрім нехтування загальними обмеженнями), але навіть у C ви повинні змусити компілятор.

Хто - то писав , що Java посилання можуть бути реалізовані в вигляді покажчиків C, до якої я говорю , звичайно, так як вони строго менш потужні, на машинах 32bit вони , як правило , є, якщо JVM реалізований в C . Хоча на машинах 64Bit, вони, як правило, стискають звичайні об'єкти-покажчики ("стиснуті OOP") для економії місця та пропускної здатності.
У будь-якому випадку ці покажчики на C також не повинні бути еквівалентними апаратним адресам, навіть якщо вони зазвичай (> 99% реалізацій) є з міркувань продуктивності.
Нарешті, це деталь реалізації, яка не піддається програмісту.


-1

Вони трохи відрізняються. У Java копія посилання копіюється в стек викликаної функції, вказуючи на той самий об'єкт, що і виклична функція, і дозволяє вам маніпулювати цим об'єктом. Однак ви не можете змінити об'єкт, на який посилається функція виклику.

Розглянемо наступний код Java

public static void changeRValue(StringBuffer sb){
    sb = new StringBuffer("helllllo"); /*attempt to assign the reference
                                        to a new object*/
}
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("hi");     //Create a new string buffer
    changeRValue(sb);                             //Call changeRValue
    System.out.println(sb.toString());            //Prints "hi" not "hello"
}

Тепер розглянемо вказівник на c ++:

void func(Dog* dog){
    *dog = Dog("hello world"); //Change the value of dog to a new object
}

int main(int argc, const char * argv[]) {
    Dog dog1("hi");                            //Create a dog object
    func(&dog1);                               //pass the address of dog
    cout << dog1.name;                         //Prints "hello world" not hi.
    return 0;
}

Я подумав, що можу додати, що це може бути схоже на const Dog *
Еладіан

2
Ви можете змінювати загострений об'єкт на Java з тією ж легкістю, що і в C ++. Вам просто потрібно мати доступ до потрібних членів. Об'єкти Java не мають операторів присвоєння, оскільки Java не підтримує визначені користувачем перевантаження, тому ви не можете використовувати перевантажений оператор, велика справа. Цей брак Java не має нічого спільного з тим, що посилання на Java є такими ж, як і С ++ вказівники, позбавлені арифметики вказівника.
Дедуплікатор
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.