Что касается вопросов этой серии, то каждый, кто изучает Java, должен их понять. Конечно, не имеет значения, если вы изучаете Java просто для развлечения. Если вы считаете, что превзошли уровень новичка, но плохо разбираетесь в этих вопросах, добавьте себя в команду новичков.
Вопрос 1: Что я утверждаю?
String s = "Привет, мир!";
Многие люди так делали, но что именно мы объявляем? Обычно ответ такой: строка с содержимым «Hello world!». Такие расплывчатые ответы часто являются источником неясных понятий. Если бы вы дали точный ответ, вероятно, половина людей ответила бы неправильно.
Этот оператор объявляет ссылку на объект с именем «s», который может указывать на любой объект типа String. В настоящее время он указывает на объект типа String «Hello world!». Вот что произошло на самом деле. Мы не объявляли объект String, мы просто объявили ссылочную переменную, которая может указывать только на объект String. Итак, если после только что сказанного вы напишете еще одно предложение:
Строка строка = с;
Мы объявили еще одну ссылку, которая может указывать только на объект String, с именем string. Никакой второй объект String по-прежнему не указывает на исходный объект, то есть он указывает на тот же объект, что и s.
Вопрос 2. В чем разница между методами «==» и «равно»?
Оператор == специально используется для сравнения значений переменных на равенство. Легче понять следующее:
Скопируйте код кода следующим образом:
интервал а=10;
интервал б=10;
Тогда a==b будет истинным.
Но вот что трудно понять:
Скопируйте код кода следующим образом:
String a=new String("foo");
String b=новая строка("foo");
Тогда a==b вернет false.
Согласно предыдущему посту, переменные объекта на самом деле являются ссылками, и их значения указывают на адрес памяти, где находится объект, а не на сам объект. И a, и b используют новый оператор, что означает, что в памяти будут сгенерированы две строки с содержимым «foo». Поскольку их «две», они, естественно, расположены по разным адресам памяти. Значения a и b на самом деле являются значениями двух разных адресов памяти, поэтому при использовании оператора «==" результат будет ложным. Это правда, что объекты, на которые указывают a и b, имеют содержимое «foo» и должны быть «равны», но оператор == не предполагает сравнение содержимого объекта.
Сравнение содержимого объекта — это именно то, что делает метод равенства.
Посмотрите, как реализован метод равенства объекта Object:
Скопируйте код кода следующим образом:
логическое равенство (Объект o) {
верните это == о;
}
Объекты объектов по умолчанию используют оператор ==. Таким образом, если ваш самостоятельно созданный класс не переопределяет метод равенства, ваш класс получит тот же результат, используя методы равенства и ==. Также можно заметить, что метод равенства объекта Object не достигает той цели, которую должен достигать метод равенства: сравнить, равно ли содержимое двух объектов. Поскольку ответ должен определить создатель класса, Object оставляет эту задачу создателю класса.
Взгляните на экстремальный класс:
Скопируйте код кода следующим образом:
Класс Монстр{
содержимое частной строки;
...
логическое равенство (Объект другой) { return true;}
}
Я переопределил метод равенства. Эта реализация приводит к тому, что сравнения между экземплярами Monster всегда возвращают true независимо от их содержимого.
Поэтому, когда вы используете метод равенства для определения равенства содержимого объекта, не принимайте это как должное. Потому что, может быть, вы думаете, что они равны, но автор этого класса так не думает, и реализация метода равенства класса контролируется им. Если вам нужно использовать метод равенства или любую коллекцию на основе хэш-кода (HashSet, HashMap, HashTable), проверьте документ Java, чтобы убедиться, как реализована логика равенства этого класса.
Вопрос 3. Изменилась ли строка?
Нет. Поскольку String спроектирован как неизменяемый класс, все его объекты являются неизменяемыми объектами. Пожалуйста, посмотрите на следующий код:
Скопируйте код кода следующим образом:
Строка s = "Привет";
s = s + "мир!";
Изменилась ли цель, на которую указывает s? Этот вывод можно легко вывести из заключения первой статьи этой серии. Давайте посмотрим, что произошло. В этом коде s изначально указывал на объект String с содержимым «Hello», а затем мы выполнили операцию + над s. Изменился ли объект, на который указывает s? Ответ — нет. В этот момент s больше не указывает на исходный объект, а на другой объект String с содержимым «Привет, мир!». Исходный объект все еще существует в памяти, но ссылочная переменная s больше не указывает на него.
Благодаря приведенному выше объяснению мы можем легко сделать еще один вывод. Если строки часто изменяются различными способами или изменяются непредвиденно, то использование String для представления строки приведет к увеличению затрат памяти. Поскольку объект String не может быть изменен после его создания, для представления каждой отдельной строки требуется объект String. В настоящее время вам следует рассмотреть возможность использования класса StringBuffer, который позволяет вносить изменения, а не создавать новый объект для каждой отдельной строки. Более того, изменение политики между этими двумя типами очень просто.
В то же время мы также можем знать, что если вы хотите использовать строку с тем же содержимым, вам не нужно каждый раз создавать новую строку. Например, если мы хотим инициализировать ссылочную переменную String с именем s в конструкторе и установить для нее начальное значение, нам следует сделать следующее:
Скопируйте код кода следующим образом:
публичный класс Демо {
частная строка s;
…
общедоступная демонстрация {
s = «Начальное значение»;
}
…
}
Вместо s = new String("Начальное значение");
Последний будет вызывать конструктор каждый раз для создания нового объекта, который имеет низкую производительность и большое потребление памяти и не имеет смысла. Поскольку объект String не может быть изменен, для представления строки с тем же содержимым можно использовать только один объект String. . Другими словами, если вы вызываете указанный выше конструктор несколько раз для создания нескольких целей, все их атрибуты типа String будут указывать на одну и ту же цель.
Приведенный выше вывод также основан на том факте, что если содержимое строковых констант одинаково, Guangzhou Java Training считает, что они представляют один и тот же объект String. Вызов конструктора с ключевым словом new всегда будет создавать новую цель, независимо от того, является ли содержимое тем же самым.
Что касается того, почему класс String следует описывать как неизменяемый класс, это определяется его назначением. Фактически, не только String, но и многие классы стандартной библиотеки классов Java являются неизменяемыми. При разработке системы нам иногда необходимо описывать неизменяемые классы для передачи набора связанных значений, что также является проявлением целенаправленного мышления. Неизменяемые классы имеют некоторые преимущества. Например, поскольку они предназначены только для чтения, не будет проблем с одновременным доступом нескольких потоков. Конечно, есть и некоторые недостатки. Например, каждая отдельная ситуация нуждается в объекте, который ее представляет, что может вызвать функциональные проблемы. Поэтому стандартная библиотека классов Java также предоставляет версию переменных, а именно StringBuffer.