Чем ссылка Java отличается от указателя C?


97

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


10
примечание, что C ++ также имеет ссылки, которые отличаются от указателей или ссылок java
jk.

@jk. Я думал, что это будет так же, как в Java. В чем разница?
Gnijuohz

17
Ссылки C ++ не могут быть повторно привязаны (т. Е. Вы не можете изменить обозначенный объект) и не обнуляемы (т. Е. Вы не можете иметь действительные ссылки на ни один объект вообще).
AProgrammer

@Gnijuohz Перефразируя сказанное @AProgrammer: finalссылка в Java почти эквивалентна ссылке на C ++. Причина, по которой они не совсем эквивалентны, заключается в том, что ссылка на C ++ дополнительно не может иметь значение null, в то время как finalссылка на Java является nullable.
Утку

Ответы:


142

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

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

В C вы можете добавить что-то к указателю (то есть адресу) или вычесть что-то, чтобы указать на то, что находится «рядом», или указать на места, которые находятся в любом месте.

В Java ссылка указывает на одну вещь и только эту вещь. Вы можете заставить переменную содержать другую ссылку, но вы не можете просто попросить ее указать «вещь после оригинальной вещи».

Ссылки строго напечатаны. Другое отличие состоит в том, что тип ссылки гораздо более строго контролируется в Java, чем тип указателя в C. В C вы можете иметь и приводить int*его к a char*и просто заново интерпретировать память в этом месте. Эта переинтерпретация не работает в Java: вы можете интерпретировать объект на другом конце ссылки как нечто, чем он уже является (то есть вы можете привести Objectссылку на Stringссылку, только если объект, на который указывает объект, фактически является a String).

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


18
+1 за мощь . Не полагайтесь на детали реализации.
CVn

2
+1 Разве сбор мусора не заслуживает упоминания в качестве конкретного жирного шрифта? Это еще один способ сделать указатели C более мощными, но и более опасными (риск зависания указателей на освобожденную память, вызывающий повреждение памяти, риск утечек памяти)
MarkJ

Другое различие между ссылками и указателями состоит в том, что указатель в C может быть преобразован в последовательность чисел (например, с помощью memcpyперемещения одного в a char[]) и наоборот. Если указатель преобразуется в последовательность чисел, которая хранится где-то (возможно, отображается на экране и копируется оператором на листке бумаги), все копии указателя в компьютере уничтожаются, и эта последовательность чисел преобразуется Возвращаясь к указателю (возможно, после ввода оператором), указатель все равно должен указывать на то же, что и раньше. Программа, которая ...
суперкат

... отображать указатель в виде чисел, а затем преобразовывать введенные вручную числа в указатель, может быть «злым», но это не вызовет никакого неопределенного поведения, если оператор не введет числа, которые, как было показано, не образуют действительного указатель. Таким образом, сборка мусора общего назначения невозможна в полностью переносимом C, поскольку компьютер никак не может узнать, существует ли копия указателя где-нибудь во вселенной.
суперкат

Согласно JLS, § 4.3.3, ссылки в Java являются указателями, поэтому «Обычно ссылки Java будут реализованы как указатели, но это не требуется в спецификации». ложно
Лью Блох

8

C ++ ссылки снова разные.

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

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


4

Ссылки Java и C указатели отличаются ровно в двух точках:

  1. Там нет указателя-арифметики для первого.
  2. И вы не можете создать ссылку на Java на то, что вы хотите, вы можете скопировать только те, которые сохранены где-нибудь доступными (статические поля, поля объектов, локальные переменные) или возвращены вызовами функций (например, вызовами конструктора), которые, таким образом, все ссылаются на Java объекты (никогда до основных типов , таких как ссылки, char, intи так далее).

Кто-то писал, что ссылки строго типизированы, потому что вы не можете заставить компилятор рассматривать a int*как a char*.
Полностью помимо того факта, что это конкретное преобразование действительно безопасно , в C нет полиморфизма, так что сравнение не является началом.
Конечно, Java более строго типизирована, чем C, не то, чтобы это особенность указателей C по сравнению с ссылками на Java, вам нужно использовать JNI, чтобы нарушить безопасность типов (помимо игнорирования общих ограничений), но даже в C вы должны заставить компилятор.

Кто-то писал, что ссылки на Java могут быть реализованы как указатели на Си, на что я уверен, поскольку они строго менее мощные, на 32-битных машинах, как это обычно бывает, если JVM реализована на Си . Хотя на 64-битных машинах они обычно сжимаются обычными объектными указателями («сжатые ООП») для экономии места и пропускной способности.
В любом случае, эти указатели 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;
}

Я подумал, что мог бы добавить, что это можно рассматривать как похожее на
конст-

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