В C ++ аргумент ссылки на функцию позволяет функции заставить ссылку ссылаться на что-то еще:
int replacement = 23;
void changeNumberReference(int& reference) {
reference = replacement;
}
int main() {
int i = 1;
std::cout << "i=" << i << "\n"; // i = 1;
changeNumberReference(i);
std::cout << "i=" << i << "\n"; // i = 23;
}
Аналогично, постоянный аргумент ссылки на функцию вызовет ошибку времени компиляции, если мы попытаемся изменить ссылку:
void changeNumberReference(const int& reference) {
reference = replacement; // compile-time error: assignment of read-only reference 'reference'
}
Теперь, в Java, документы говорят, что аргументы функций непримитивных типов являются ссылками. Пример из официальных документов:
public void moveCircle(Circle circle, int deltaX, int deltaY) {
// code to move origin of circle to x+deltaX, y+deltaY
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
// code to assign a new reference to circle
circle = new Circle(0, 0);
}
Тогда окружности присваивается ссылка на новый объект Circle с x = y = 0. Однако это переназначение не имеет постоянства, поскольку ссылка была передана по значению и не может быть изменена.
Для меня это совсем не похоже на ссылки на C ++. Он не похож на обычные ссылки C ++, потому что вы не можете заставить его ссылаться на что-то другое, и он не похож на константные ссылки C ++, потому что в Java код, который изменит (но на самом деле не делает) ссылку, не вызывает компиляцию ошибка
По поведению это больше похоже на указатели C ++. Вы можете использовать его для изменения значений указанных объектов, но вы не можете изменить само значение указателя в функции. Кроме того, как и в случае с указателями C ++ (но не со ссылками на C ++), в Java вы можете передать «null» в качестве значения для такого аргумента.
Итак, мой вопрос: почему Java использует понятие «ссылка»? Следует ли понимать, что они не похожи на ссылки C ++? Или они действительно напоминают ссылки на C ++, а я что-то упустил?
Ответы:
Зачем? Поскольку, хотя согласованная терминология, как правило, полезна для всей профессии, разработчики языка не всегда уважают использование языка другими разработчиками языка, особенно если эти другие языки воспринимаются как конкуренты.
Но на самом деле ни использование «ссылки» не было очень хорошим выбором. «Ссылки» в C ++ - это просто языковая конструкция, чтобы представить явного псевдонимов (альтернативных имен для одной и той же сущности). Все было бы намного яснее, если бы они просто называли новую функцию «псевдонимами». Однако в то время большая трудность состояла в том, чтобы заставить всех понять разницу между указателями (которые требуют разыменования) и ссылками (которые этого не делают), поэтому важно было то, что он назывался не «указателем», а не так. более конкретно, какой термин использовать.
Java не имеет указателей и гордится этим, поэтому использование «указателя» в качестве термина не было вариантом. Тем не менее, «ссылки», которые он выполняет, ведут себя немного так же, как указатели в C ++, когда вы их передаете, - большая разница в том, что вы не можете выполнять над ними более низкоуровневые операции (приведение, добавление ...) , но они приводят к точно такой же семантике, когда вы передаете дескрипторы идентичным сущностям по сравнению с сущностями, которые просто оказываются равными. К сожалению, термин «указатель» несет в себе так много негативных низкоуровневых ассоциаций, что это вряд ли когда-либо будет принято сообществом Java.
В результате оба языка используют один и тот же расплывчатый термин для двух довольно разных вещей, оба из которых могут получить выгоду от более конкретного имени, но ни один из которых, вероятно, не будет заменен в ближайшее время. Естественный язык тоже может иногда расстраивать!
источник
NullPointerException
того факта, что JLS использует термин «указатель»?NullPointerException
не указатель, но исключение, указывающее, что на более низком уровне указатель NULL был передан / разыменован. ИспользованиеPointer
в качестве исключения, если что-либо, добавляет к неприятному образу, который у них есть. JLS должен упоминать указатели, потому что виртуальная машина Java была написана в основном на языке, который их использует. Вы не можете точно описать языковые спецификации, не описав, как работают внутренние устройстваСсылка - это вещь, которая относится к другой вещи. Различные языки придают более конкретное значение слову «ссылка», обычно «что-то вроде указателя без всех плохих аспектов». C ++ придает особое значение, как и Java или Perl.
В C ++ ссылки больше похожи на псевдонимы (которые могут быть реализованы с помощью указателя). Это позволяет передавать по ссылке или из аргументов .
В Java ссылки являются указателями, за исключением того, что это не конкретизированная концепция языка: все объекты являются ссылками, а примитивные типы, такие как числа, - нет. Они не хотят произносить «указатель», потому что в Java нет арифметики указателей и нет указателей reified, но они хотят прояснить, что при передаче
Object
в качестве аргумента объект не копируется . Это также не передача по ссылке , а что-то более похожее на передачу .источник
Это в основном восходит к Алголу 68, и частично к реакции на то, как С определяет указатели.
Алгол 68 определил понятие, называемое ссылкой. Это было почти так же, как (для одного примера) указатель в Паскале. Это была ячейка, которая содержала либо NIL, либо адрес какой-то другой ячейки определенного типа. Вы можете назначить ссылку, чтобы ссылка могла ссылаться на одну ячейку за раз и на другую ячейку после переназначения. Однако он не поддерживает ничего похожего на арифметику указателей в C или C ++.
Однако, по крайней мере, как определил Алгол 68, ссылки были довольно чистым понятием, которое было довольно неуклюжим для использования на практике. Большинство определений переменных были на самом деле ссылками, поэтому они определили сокращенную запись, чтобы не дать ей полностью выйти из-под контроля, но любое более простое использование в любом случае могло довольно быстро стать неуклюжим.
Например, объявление like
INT j := 7;
было действительно обработано компилятором как объявление likeREF INT j = NEW LOC INT := 7
. Итак, то, что вы объявили в Algol 68, обычно было ссылкой, которая затем инициализировалась для ссылки на что-то, что было выделено в куче, и это (необязательно) было инициализировано, чтобы содержать некоторое указанное значение. Однако, в отличие от Java, они, по крайней мере, пытались позволить вам поддерживать нормальный синтаксис для этого, вместо того, чтобы постоянно иметь подобные вещиfoo bar = new foo();
или пытаться рассказывать выдумкам о том, что «наши указатели не являются указателями».Паскаль и большинство его потомков (как прямых, так и ... духовных) переименовали эталонную концепцию Algol 68 в «указатель», но оставили саму концепцию по существу такой же: указатель был переменной, которая содержала либо
nil
адрес чего-то, что вы выделили в куче (т. е. по крайней мере, как изначально определено Дженсеном и Виртом, не было оператора «address-of», поэтому у указателя не было возможности ссылаться на нормально определенную переменную). Несмотря на то, что они были «указателями», арифметика указателей не поддерживалась.C и C ++ добавили несколько поворотов к этому. Во- первых, они делают имеют адрес-оператора, поэтому указатель может относиться не только к чему - то выделенной в куче, но и к любой переменной, независимо от того, как он выделяется. Во-вторых, они определяют арифметику для указателей - и определяют индексы массива как в основном просто сокращенную запись для арифметики указателей, поэтому арифметика указателей повсеместна (рядом с неизбежной) в большинстве C и C ++.
Когда изобрели Java, Sun, по-видимому, думал, что «Java не имеет указателей» было более простым и понятным маркетинговым сообщением, чем: «почти все в Java является указателем, но эти указатели в основном похожи на Паскаль, а не на С». Поскольку они решили, что «указатель» не является приемлемым термином, им нужно было что-то еще, и вместо этого они взяли «ссылку», хотя их ссылки слегка (а в некоторых случаях не так тонко) отличались от ссылок на Алгол 68.
Хотя все вышло несколько иначе, в C ++ возникла примерно та же проблема: слово «указатель» уже было известно и понято, поэтому им нужно было другое слово для этой другой вещи, которую они добавляли, которая ссылалась на что-то другое, но в остальном это было довольно немного отличается от того, что люди понимают под «указателем». Таким образом, хотя он также заметно отличается от ссылки на Algol 68, они также повторно использовали термин «ссылка».
источник
Понятие «ссылочный тип» является общим, оно может выражать как указатель, так и ссылку (в терминах C ++), а не «тип значения». Ссылки Java являются действительно указатели без синтаксического погона
->
с*
разыменования. Если вы посмотрите на реализацию JVM в C ++, они действительно голые указатели. Кроме того, в C # есть понятие ссылок, аналогичное Java, но также есть указатели и квалификаторы 'ref' на параметры функции, позволяющие передавать типы значений по ссылке и избегать копирования, как&
в C ++.источник