Java не имеет указателей; У Java есть ссылки.
Это замечательно, но у указателя есть дополнительные операции, которые вы можете (или не можете) обычно использовать; в ссылке отсутствуют эти операции, поскольку операции могут быть небезопасными.
Например, если вы используете указатель для индексации первого элемента массива, например:
int squares[] = {1, 4, 9, 16, 25, 36, 49};
int* intPointer = squares;
вы можете разыменовать указатель и получить значение «1», но вы также можете:
intPointer++
и после этого при разыменовании указателя вы получите значение «4». Второй
intPointer++;
при разыменовании даст вам значение "9". Это связано с тем, что операция ++ перемещает указатель на одну единицу вперед в памяти.
Проблема связана с недостатками системы проверки типов C / C ++ (C ++ должен поддерживать совместимость с C, поэтому допускает те же проблемы). Указатель хранит адрес в памяти, а операция ++ добавляет соответствующее количество байтов к адресу. Во многих системах ++ использование int добавляет четыре байта, но если указатель был указателем char ++, то он должен добавлять только один байт. Обратите внимание, что поскольку базовый тип данных указателя является адресом в памяти, допустимо следующее (но не рекомендуется):
char* charPointer = squares;
charPointer++;
void* voidPointer = squares;
voidPointer++;
Поскольку указатели являются адресами в памяти, они могут (правильно) представлять любой бит памяти в компьютере, но на них должным образом разыменовываются, только когда базовые данные соответствуют типу и выравниванию указателя. Для указателей, которые не управляются большим количеством кода для обеспечения их безопасности, это означает, что вы можете отклониться от типа данных (или выравнивания) требуемой информации, и разыменование может закончиться катастрофой. Попытка исправить эту проблему с помощью пользовательского кода имеет тенденцию настолько сильно тормозить работу одного указателя, что вы замечаете проблемы с производительностью, и это открывает двери для добавления ошибок в пользовательский код «управления указателями».
Сторона Java решает все эти проблемы, возвращая ссылку. Ссылка не ссылается на какое-либо место в памяти; Java поддерживает внутреннюю таблицу «ссылка на указатель». Эта таблица берет ссылку и возвращает данные, связанные с ней, где бы эти данные не находились в памяти. Это замедляет выполнение кода, поскольку для каждой «разыменования» выполняется два поиска, один поиск в справочной таблице, другой в памяти машины.
Большим преимуществом использования ссылок на Java является то, что память можно перемещать, не нарушая адреса потенциальных указателей. В программе на Си, если вы перемещаете данные в новое место в памяти, очень трудно узнать, имеет ли какая-либо другая часть программы указатель на данные. Если устаревший указатель будет разыменован после перемещения памяти, программа получит доступ к поврежденным данным, и, как правило, происходит сбой.
Возможность перемещать память в запущенной программе позволяет программам легко перезаписывать память. Любая программа, которая не нуждается в порциях памяти, может освободить неиспользуемую память, но это создает дыры в памяти неиспользуемой памяти между порциями используемой памяти. Внутренне компьютеры используют страницы памяти, которые довольно велики. Если на редко используемой странице памяти могут быть перемещены несколько использованных битов на другую страницу, то страница памяти может быть освобождена. Это увеличивает плотность данных в памяти, улучшая производительность кеша. Иногда это приводит к улучшению производительности, которое может быть весьма значительным.
Сборщик мусора в Java использует преимущества ссылок, временно блокируя доступ к данным для набора ссылок. Во время этой блокировки доступа он перемещает данные (для их сжатия). После блокировки ссылка на таблицу адресов имеет новые адреса памяти. Поскольку «функциональный» слой кода никогда не знал адресов в первую очередь, эта операция не сломает работающую Java-программу.