Работа с массивами, класс String и его методы, StringBuilder.
Массив — это упорядоченная коллекция элементов одного типа, хранящаяся в памяти подряд. Представь его как нумерованный шкафчик, где каждая ячейка имеет свой номер (индекс) и хранит одно значение.
Есть несколько способов:
// Способ 1: объявление + создание + заполнение по элементам
int[] numbers = {10, 20, 30, 40, 50};
// Способ 2: объявление + создание пустого массива заданного размера
int[] scores = new int[5]; // 5 ячеек, заполнены нулями по умолчанию
// Способ 3: объявление + создание + заполнение по одному
String[] names = new String[3];
names[0] = "Вика";
names[1] = "Аня";
names[2] = "Маша";⚠️ Важно: размер массива нельзя изменить после создания. Если нужно больше — создаётся новый массив.
Индексы начинаются с 0. Это одна из самых частых ошибок у новичков!
String[] fruits = {"яблоко", "банан", "апельсин"};
System.out.println(fruits[0]); // "яблоко"
System.out.println(fruits[1]); // "банан"
System.out.println(fruits[2]); // "апельсин"
System.out.println(fruits.length); // 3 — длина массива
fruits[1] = "груша"; // изменяем элемент
// fruits[3] = "киви"; // 💥 ArrayIndexOutOfBoundsException — выход за границы!Если создать массив без заполнения, Java сама заполнит его «нулевыми» значениями:
| Тип | Значение по умолчанию |
|---|---|
| int, long, short, byte | 0 |
| double, float | 0.0 |
| boolean | false |
| char | '\u0000' (пустой символ) |
| Ссылочные типы (String, объекты) | null |
int[] numbers = {10, 20, 30, 40, 50};
// Через обычный for (когда нужен индекс)
for (int i = 0; i < numbers.length; i++) {
System.out.println("Индекс " + i + ": " + numbers[i]);
}
// Через for-each (когда индекс не важен)
for (int num : numbers) {
System.out.println(num);
}Массив может содержать другие массивы. Классический пример — матрица (таблица чисел).
int[][] grid = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};import java.util.Arrays;
int[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr); // Сортировка: [1, 2, 5, 8, 9]
System.out.println(Arrays.toString(arr)); // Красивый вывод: "[1, 2, 5, 8, 9]"
Arrays.fill(arr, 0); // Заполнить все нулями
int[] copy = Arrays.copyOf(arr, 10); // Скопировать в массив размером 10
boolean isEqual = Arrays.equals(arr, copy); // Сравнение двух массивовСтрока в Java — это последовательность символов. Но технически String — это класс (объект), а не примитивный тип.
String s1 = "Привет"; // Литерал (самый частый способ)
String s2 = new String("Привет"); // Через конструктор (редко используется)
String s3 = ""; // Пустая строка
String s4 = null; // Строки нет вообщеЭто критически важно! После создания объект String нельзя изменить. Любая «модификация» создаёт новый объект.
String s = "Привет";
s = s + ", мир!"; // Это НЕ изменило старый объект!
// Создался НОВЫЙ объект "Привет, мир!", и s теперь ссылается на негоString s1 = "Привет";
String s2 = "Привет";
String s3 = new String("Привет");
System.out.println(s1 == s2); // true (ссылаются на один объект в string pool)
System.out.println(s1 == s3); // false (разные объекты!)
System.out.println(s1.equals(s3)); // true ✅ (сравниваем СОДЕРЖИМОЕ)
System.out.println(s1.equalsIgnoreCase("ПРИВЕТ")); // true (без учёта регистра)⚠️ Правило: для сравнения строк всегда используй .equals(), а не ==.
String s = " Hello, World! ";
// Длина и доступ к символам
s.length(); // 19
s.charAt(0); // ' ' (первый символ)
s.charAt(s.length()-1); // ' ' (последний символ)
// Поиск
s.indexOf("World"); // 9 (индекс, с которого начинается "World")
s.contains("Hello"); // true
s.startsWith(" He"); // true
s.endsWith("! "); // true
// Извлечение подстрок
s.substring(9, 14); // "World" (с 9 по 13 включительно)
// Преобразование регистра
s.toUpperCase(); // " HELLO, WORLD! "
s.toLowerCase(); // " hello, world! "
// Удаление пробелов
s.trim(); // "Hello, World!" (только по краям)
s.strip(); // "Hello, World!" (современный аналог, лучше работает с Unicode)
// Замена
s.replace("World", "Java"); // " Hello, Java! "
// Разбиение и объединение
String csv = "apple,banana,cherry";
String[] parts = csv.split(","); // ["apple", "banana", "cherry"]
String joined = String.join(" | ", "Вика", "Аня", "Маша"); // "Вика | Аня | Маша"
// Проверки
"".isEmpty(); // true (длина 0)
" ".isBlank(); // true (только пробелы, Java 11+)
"123".matches("\\d+"); // true (регулярное выражение: только цифры)
// Преобразования типов
String.valueOf(42); // "42"
Integer.parseInt("123"); // 123 (String → int)
Double.parseDouble("3.14"); // 3.14String name = "Вика";
int age = 25;
double height = 1.68;
// Способ 1: String.format (как printf в C)
String info = String.format("Имя: %s, возраст: %d, рост: %.2f", name, age, height);
// "Имя: Вика, возраст: 25, рост: 1.68"
// Способ 2: Text blocks (Java 15+) — для многострочных строк
String json = """
{
"name": "%s",
"age": %d
}
""".formatted(name, age);String s = "Привет, " + "Вика" + "!"; // Нормально для простых случаев
// Но в цикле — ПЛОХО:
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // На каждой итерации создаётся НОВЫЙ объект String!
// 1000 итераций = 1000 созданных объектов = медленно и жрёт память
}Для сборки строк в цикле используй StringBuilder 👇
StringBuilder — это «изменяемая» строка. В отличие от String, его содержимое можно модифицировать без создания новых объектов.
StringBuilder sb = new StringBuilder();
sb.append("Привет"); // Добавить в конец: "Привет"
sb.append(", "); // "Привет, "
sb.append("Вика"); // "Привет, Вика"
sb.append("!"); // "Привет, Вика!"
sb.insert(8, "дорогая "); // Вставить на позицию 8: "Привет, дорогая Вика!"
sb.delete(8, 16); // Удалить с 8 по 15: "Привет, Вика!"
sb.replace(8, 13, "Аня"); // Заменить: "Привет, Аня!"
sb.reverse(); // Перевернуть: "!Аня ,тевирП"
int length = sb.length(); // Длина
String result = sb.toString(); // Превратить обратно в String| Класс | Потокобезопасность | Скорость |
|---|---|---|
| StringBuilder | ❌ Нет | Быстрый |
| StringBuffer | ✅ Да | Медленнее |
В 99% случаев используй StringBuilder. StringBuffer нужен только если с одной строкой работают несколько потоков одновременно (редкий случай).
public class VowelCounter {
public static void main(String[] args) {
String text = "Hello, World!";
String vowels = "aeiouAEIOU";
int count = 0;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (vowels.indexOf(c) != -1) {
count++;
}
}
System.out.println("Гласных: " + count); // 3 (e, o, o)
}
}public class Palindrome {
public static boolean isPalindrome(String s) {
// Очищаем строку: убираем пробелы и приводим к нижнему регистру
String clean = s.replaceAll("\\s+", "").toLowerCase();
int left = 0;
int right = clean.length() - 1;
while (left < right) {
if (clean.charAt(left) != clean.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
public static void main(String[] args) {
System.out.println(isPalindrome("А роза упала на лапу Азора")); // true
System.out.println(isPalindrome("Hello")); // false
}
}public class MaxFinder {
public static void main(String[] args) {
int[] numbers = {5, 2, 9, 1, 7, 3};
int max = numbers[0]; // Начинаем с первого элемента
int maxIndex = 0;
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > max) {
max = numbers[i];
maxIndex = i;
}
}
System.out.println("Максимум: " + max + " (индекс: " + maxIndex + ")");
// Максимум: 9 (индекс: 2)
}
}public class BubbleSort {
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// Меняем местами
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
// [11, 12, 22, 25, 34, 64, 90]
}
}Попробуй решить самостоятельно:
Сумма элементов массива — дан массив целых чисел. Найди их сумму и среднее арифметическое.
Реверс строки — напиши метод, который разворачивает строку задом наперёд (например, "Привет" → "тевирП"). Сделай два варианта: через StringBuilder и вручную через цикл.
Подсчёт символов — дана строка. Посчитай, сколько раз встречается каждая буква (без учёта регистра). Выведи результат в виде: а: 5, б: 2, ....
Поиск дубликатов — дан массив чисел. Найди все числа, которые встречаются более одного раза.
Шифр Цезаря — напиши программу, которая сдвигает каждую букву в строке на N позиций в алфавите (например, "Привет" со сдвигом 3 → "Сулезw").
Разворот строки Условие: Напиши метод, который разворачивает строку задом наперёд. Использовать StringBuilder.reverse() нельзя. Пример: "Привет" → "тевирП"
💡 Подсказка: Преобразуй в char[] и меняй местами символы с двух концов, двигаясь к центру.
Проверка палиндрома Условие: Проверь, является ли строка палиндромом (читается одинаково в обоих направлениях). Игнорируй регистр и не-буквенные символы. Пример: "А роза упала на лапу Азора" → true Пример: "Hello" → false
💡 Подсказка: Два указателя — один с начала, другой с конца. Пропускай пробелы и знаки препинания.
Первая уникальная буква Условие: Найди индекс первого символа в строке, который не повторяется. Если такого нет — верни -1. Пример: "java" → 0 (буква 'j') Пример: "aabb" → -1
💡 Подсказка: Первый проход — считаем частоты каждой буквы (массив на 26/256 ячеек). Второй проход — ищем первую с частотой 1.
Проверка анаграмм Условие: Проверь, являются ли две строки анаграммами (состоят из одних и тех же букв в одинаковом количестве). Пример: "listen" и "silent" → true Пример: "hello" и "world" → false
💡 Подсказка: Либо отсортировать оба массива символов и сравнить, либо посчитать частоты букв.
Перемещение нулей в конец Условие: Перемести все нули в массиве в конец, сохранив порядок остальных элементов. Делай это "на месте" (in-place). Пример: [0, 1, 0, 3, 12] → [1, 3, 12, 0, 0]
💡 Подсказка: Два указателя. Один идёт по массиву и собирает ненулевые элементы в начало, второй следит за позицией для записи.
Сдвиг массива на K позиций Условие: Сдвинь массив вправо на K позиций циклически. Пример: [1, 2, 3, 4, 5, 6], K = 2 → [5, 6, 1, 2, 3, 4]
💡 Подсказка: Трюк с тремя реверсами: разверни весь массив → разверни первые K элементов → разверни оставшиеся.
Поиск двух чисел с заданной суммой Условие: В массиве найди два числа, которые в сумме дают заданное target. Верни их индексы. Пример: [2, 7, 11, 15], target = 9 → [0, 1]
💡 Подсказка: Используй HashMap, где ключ — число, значение — его индекс. Для каждого элемента проверяй, есть ли в карте target - num.
Сжатие строки (Run-Length Encoding) Условие: Сожми строку, заменяя последовательности одинаковых символов на символ + количество. Пример: "aaabbc" → "a3b2c1" Пример: "abc" → "a1b1c1"
💡 Подсказка: Иди по строке, считая длину текущей группы одинаковых символов. Когда символ меняется — записывай в результат.
12💡 Подсказка: Техника "скользящее окно". Два указателя (левый и правый) + HashSet или массив для отслеживания позиций символов.
1💡 Подсказка: Два указателя, по одному на каждый массив. На каждом шаге сравнивай текущие элементы и добавляй меньший в результат.
Значения String хранятся в пуле стрингов (constant string pool). Как только будет создана строка, она появится в этом пуле. И удалить ее будет нельзя.
Например:
String name = "book";
...переменная будет ссылаться на стринг пул

Если задать переменной name другое значение, получится следующее:
name = "pen";

Таким образом, эти два значения так и останутся там.
String Buffer: значения String хранятся в стеке(Stack). Если значение изменено, значит новое значение будет заменено на старое; String Buffer синхронизирован, и поэтому он потокобезопасный; из-за потокобезопасности скорость работы оставляет желать лучшего.
Пример:
StringBuffer name = "book";

Как только значение name сменится, в стеке измениться значение:

StringBuilder
Точно такой же, как и StringBuffer, только он не потокобезопасный. Поэтому скорость его явно выше, чем в StringBuffer.
String — стандартный класс в Java, отвечающий за хранение и манипуляции со строковыми значениями (последовательности символов), является immutable классом (об immutable я писал ранее), т.е. данные объектов данного класса невозможно изменить после создания.
Хотелось бы сразу отметить, что классы StringBuilder и StringBuffer — это два фактически одинаковых класса с той лишь разницей, что один из них предназначен для использования в многопоточной среде (StringBuffer).
Эти классы являются аналогами String, но в отличие от него они изменяемы.
То есть объекты после создания допускают модификацию строки, которую представляют, без создания нового объекта.
Собственно, методы отличаются от стандартных методов String и направлены на удовлетворение потребностей по изменению строки (не зря же builder-ом назвали).
Самый привычный способ создания строки — простое задание нужного нам значения в двойных скобках:
String str = "Hello World!";
Также можно сделать это непосредственно через new:
String str = new String("Hello World!");
Можно создать строку и отталкиваясь от массива символов:
char[] charArr = {'H','e','l','l','o',' ', 'W','o','r','l','d','!'};
String str = new String(charArr);Как результат работы метода toString на некотором объекте:
String str = someObject.toString();
Как результат работы любого другого метода возвращает строковое представление. Например:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String str = reader.readLine();Как вы поняли, способов создания строки может быть очень и очень много.
При создании объекта String он сохраняется в строковом пуле, о котором подробнее мы поговорим в одном из вопросов далее.
Для сравнения значений в Java используется знак двойного равно ==.
Если бы нам нужно было сравнивать некоторые простые значения вроде int, мы бы воспользовались им.
Но для сравнения полноценных объектов данный способ неприменим. В таком случае это будет лишь сравнение ссылок — указывают ли они на один и тот же они объект или нет. То есть при сравнении двух объектов с совершенно одинаковыми значениями внутренних полей сравнение через == даст результат false: несмотря на одинаковость полей объектов, сами объекты занимают разные ячейки памяти.
А объекты класса String, несмотря на обманчивую простоту, всё же являются объектами. И сравнение через == для них также неприменимо (даже несмотря на наличие строкового пула).
Тут за дело берется стандартный метод класса Object — equals, который необходимо переопределить в классе для его корректной работы (иначе по умолчанию он сравнивает через ==).
В классе String он переопределен, значит просто берем и используем его:
String firstStr = "Hello World!";
String secondStr = "Hello World!";
boolean isEquals = firstStr.equals(secondStr);Мы говорили о сравнении на соответствие, а теперь разберем сравнение для сортировки. Ведь для сортировки чего-либо нам нужно знать, по какому принципу сортировать. Для этого можно воспользоваться стандартным отсортированным множеством — TreeSet.
Подробнее о различных коллекциях в Java вы можете почитать в этой статье.
Данный список работает на основе алгоритма красно-черного дерева и сортирует множество в соответствии с заданным принципом сортировки.
Как я и сказал ранее, нужно понимать, как отсортировать объекты определенного типа. Чтобы задать способ сравнения для сортировки, используют компараторы.
Как правило их необходимо реализовывать для классов, которые вы хотите сортировать, но в случае со String они уже реализованы.
Поэтому просто добавляем нужные нам строки в TreeSet, а он их отсортирует:
TreeSet<String> sortedSet = new TreeSet<>();
sortedSet.add("B");
sortedSet.add("C");
sortedSet.add("A");
sortedSet.forEach(System.out::println);Вывод в консоли:
A
B
C
``
### 5) Приведите алгоритм перевода строки в символ. Напишите соответствующий код
Как я и говорил ранее, у объектов класса String очень много разных полезных методов. Один из таких — toCharArray. Данный метод переводит строку в массив символов:
```java
String str = "Hello world";
char[] charArr = str.toCharArray();Далее у нас есть массив символов, которые можем вызывать по индексу:
char firstChar = charArr[0]; // H
Аналогичный методу toCharArray, класс String имеет метод getBytes, который возвращает массив байтов строки:
String str = "Hello world";
byte[] byteArr = str.getBytes();
byte firstChar = byteArr[6]; // 119В памяти в Java (Heap, о которой мы ещё поговорим) есть область — String pool, или строковый пул.
Она предназначена для хранения строковых значений. Другими словами когда вы создаете некую строку, например через двойные кавычки:
String str = "Hello world";
происходит проверка того, имеет ли строковой пул данное значение.
Если имеет, переменной str присваивается ссылка на это значение в пуле. Если же не имеет, создастся новое значение в пуле, и ссылка на него будет присвоена переменной str.
Рассмотрим пример:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);На экран будет выведено true. Мы помним, что == сравнивает именно ссылки — значит эти две ссылки ссылаются на одно и то же значение из строкового пула.
Это сделано для того, чтобы не плодить множество одинаковых объектов типа String в памяти, ведь как мы помним, String — неизменяемый класс, и если у нас будет множество ссылок на одно и то же значение, плохого в этом ничего нет. Теперь невозможна ситуация, при которой изменение значения в одном месте приводит к изменениям сразу для нескольких других ссылок.
Но тем не менее, если мы создадим строку через new:
String str = new String("Hello world");
создастся отдельный объект в памяти, который будет хранить данное строковое значение (и не важно, есть ли у нас уже такое значение в строковом пуле).
В качестве подтверждения:
String firstStr = new String("Hello world");
String secondStr = "Hello world";
String thirdStr = new String("Hello world");
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);Мы получим два false, и это значит, что у нас тут три разные значения, на которые ссылаются ссылки. Собственно, поэтому рекомендуется создавать строки просто через двойные кавычки.
Тем не менее, можно сложить (или получать ссылку) значения в строковой пул и при создании объекта через new. Для этого используем метод класса строки — intern(). Данный метод принудительно создает значение в строковом пуле, ну или получает ссылку на него, если оно уже хранится там.
Вот пример:
String firstStr = new String("Hello world").intern();
String secondStr = "Hello world";
String thirdStr = new String("Hello world").intern();
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
System.out.println(secondStr == thirdStr);в результате мы получим в консоли три значения true, а значит, все три переменные ссылаются на одну и ту же строку.
В строковом пуле явно прослеживается GOF шаблон — легковес (flyweight), иначе его называют поселенец. Если же вы увидели тут ещё какой-то шаблон — делитесь в комментарии.
Ну а мы поговорим о шаблоне легковесе.
Легковес — структурный шаблон проектирования, при котором объект, представляющий себя как уникальный экземпляр в разных местах программы, по факту не является таковым. Легковес экономит память, разделяя общее состояние объектов между собой, вместо хранения одинаковых данных в каждом объекте.
Для понимания сути рассмотрим самый простой пример. Предположим, у нас есть интерфейс сотрудника:
public interface Employee {
void work();
}И есть некоторые реализации, например, юрист:
public class Lawyer implements Employee {
public Lawyer() {
System.out.println("Юрист взят в штат.");
}
@Override
public void work() {
System.out.println("Решение юридических вопросов...");
}
}И бухгалтер:
public class Accountant implements Employee{
public Accountant() {
System.out.println("Бухгалтер взят в штат.");
}
@Override
public void work() {
System.out.println("Ведение бухгалтерского отчёта....");
}
}Методы весьма условны: нам всего лишь нужно видеть, что они выполняются. Такая же ситуация и с конструктором. Благодаря выводу в консоли мы будем видеть, когда создаются новые объекты.
Также у нас есть отдел сотрудников, задача которого — выдавать запрашиваемого сотрудника, если же его нет — нанимать в штат и выдавать в ответ на запрос:
public class StaffDepartment {
private Map<String, Employee> currentEmployees = new HashMap<>();
public Employee receiveEmployee(String type) throws Exception {
Employee result;
if (currentEmployees.containsKey(type)) {
result = currentEmployees.get(type);
} else {
switch (type) {
case "Бухгалтер":
result = new Accountant();
currentEmployees.put(type, result);
break;
case "Юрист":
result = new Lawyer();
currentEmployees.put(type, result);
break;
default:
throw new Exception("Данный сотрудник в штате не предусмотрен!");
}
}
return result;
}
}То есть логика простая: если есть данная единица — верни её, если нет — создай, помести в хранилище (что-то вроде кеша) и отдай назад.
А теперь давайте посмотрим, как это всё работает:
public static void main(String[] args) throws Exception {
StaffDepartment staffDepartment = new StaffDepartment();
Employee empl1 = staffDepartment.receiveEmployee("Юрист");
empl1.work();
Employee empl2 = staffDepartment.receiveEmployee("Бухгалтер");
empl2.work();
Employee empl3 = staffDepartment.receiveEmployee("Юрист");
empl1.work();
Employee empl4 = staffDepartment.receiveEmployee("Бухгалтер");
empl2.work();
Employee empl5 = staffDepartment.receiveEmployee("Юрист");
empl1.work();
Employee empl6 = staffDepartment.receiveEmployee("Бухгалтер");
empl2.work();
Employee empl7 = staffDepartment.receiveEmployee("Юрист");
empl1.work();
Employee empl8 = staffDepartment.receiveEmployee("Бухгалтер");
empl2.work();
Employee empl9 = staffDepartment.receiveEmployee("Юрист");
empl1.work();
Employee empl10 = staffDepartment.receiveEmployee("Бухгалтер");
empl2.work();
}И в консоли, соответственно, будет вывод:
Юрист взят в штат.
Решение юридических вопросов...
Бухгалтер взят в штат.
Ведение бухгалтерского отчёта....
Решение юридических вопросов...
Ведение бухгалтерского отчёта....
Решение юридических вопросов...
Ведение бухгалтерского отчёта....
Решение юридических вопросов...
Ведение бухгалтерского отчёта....
Решение юридических вопросов...
Ведение бухгалтерского отчёта...Как вы видите, всего было создано лишь два объекта, которые при этом многократно переиспользовались.
Пример весьма простой, но он наглядно демонстрирует как применение данного шаблона может сэкономить наши ресурсы. Ну и как вы заметили, логика данного паттерна уж больно похожа на логику работы страхового пула.
Подробнее о разновидностях GOF паттернов вы можете почитать в этой статье.
Очевидно, что в данном вопросе речь идёт о методе split. У класса String есть две вариации данного метода:
String split(String regex);
и
String split(String regex);
regex — это разделитель строки — некоторое регулярное выражение, по которому производится разделение строки на массив строк, например:
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
System.out.println(s);
}```
В консоль будет выведено:
```Hello,
world
it's
Amigo!То есть, наше строковое значение было разбито на массив строк и разделителем послужил пробел (для разделения можно было использовать и не регулярное выражение пробела "\s" и просто строковое выражение " ").
Второй, перегруженный метод имеет дополнительный аргумент — limit.
limit — максимально допустимое значение получаемого массива. То есть, когда строка будет уже разбита на предельное допустимое количество подстрок, дальнейшей разбивки не будет, и у последнего элемента будет “остаток” от возможно недоразбитой строки.
Пример:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
System.out.println(s);
}```
Вывод в консоли:
```Hello,
world it's Amigo!Как мы видим, если бы не ограничение limit = 2, последний элемент массива можно было бы разбить на три подстроки.
Причин для предпочтения массива строке при сохранении пароля несколько:
char[]) мы можем явно стереть данные после того, как закончили работу с ним. Также мы можем сколько угодно переписывать массив, и действительного пароля нигде не будет в системе, даже до сбора мусора (достаточно изменить пару ячеек на недействительные значения).
В то самое время String — immutable класс. То есть, если мы хотим изменить его значение, мы получим новое, а старое при этом останется в строковом пуле. Если мы захотим удалить String значение пароля, это может быть весьма сложным занятием, так как нужно, чтобы сборщик мусора удалил именно значение из String pool-а, и существует большая вероятность, что это String значение останется там надолго.
То есть, в данной ситуации String уступает массиву char в безопасности хранения данных.
String password = "password";
System.out.println("Пароль - " + password);Вывод в консоли:
Пароль - password
В то же время, если случайно вывести в консоль массив:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);в консоли будет непонятная абракадабра:
Пароль - [C@7f31245a
На самом деле не абракадабра, а:
[C — имя класса — массив char, @ — разделитель, после которого — 7f31245a — шестнадцатеричный хешкод.