← Назад к вопросам

Сравнение строк: == vs equals()

1.0 Junior🔥 151 комментариев
#Другое#Основы Java

Условие

Предскажите результат выполнения следующего кода:

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = new String("Hello");

System.out.println(s1 == s2);         // ?
System.out.println(s1 == s3);         // ?
System.out.println(s1.equals(s3));    // ?
System.out.println(s3 == s4);         // ?
System.out.println(s3.equals(s4));    // ?

Вопросы

  1. Каков результат каждого сравнения?
  2. Что такое String Pool?
  3. В чём разница между == и equals()?
  4. Когда использовать == и когда equals()?

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Сравнение строк: == vs equals()

Это один из самых частых вопросов на собеседованиях Java-разработчиков, и ответ требует глубокого понимания того, как Java работает со строками. Давайте разберёмся с примерами.

Результаты выполнения кода

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = new String("Hello");

System.out.println(s1 == s2);         // true ✅
System.out.println(s1 == s3);         // false ❌
System.out.println(s1.equals(s3));    // true ✅
System.out.println(s3 == s4);         // false ❌
System.out.println(s3.equals(s4));    // true ✅

Почему такие результаты?

Сравнение s1 == s2true

Обе переменные указывают на один и тот же объект в String Pool:

┌─────────────────────────┐
│    String Pool (Heap)   │
├─────────────────────────┤
│   "Hello" (объект)     │◄─── s1
└─────────────────────────┘       s2

Когда вы создаёте строку с использованием литерала (например, "Hello"), Java проверяет, существует ли такая строка в String Pool. Если существует — переиспользует существующий объект.

Сравнение s1 == s3false

s3 создаётся с помощью new String(), что создаёт новый объект в Heap:

┌─────────────────────────┐
│    String Pool (Heap)   │
├─────────────────────────┤
│   "Hello" (объект 1)   │◄─── s1
└─────────────────────────┘

┌─────────────────────────┐
│       Heap (память)     │
├─────────────────────────┤
│   "Hello" (объект 2)   │◄─── s3
└─────────────────────────┘

Оператор == сравнивает ссылки (адреса в памяти), а не содержимое. Разные объекты = разные ссылки = false.

Сравнение s1.equals(s3)true

Метод equals() сравнивает содержимое строк, а не их ссылки:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;  // Если ссылки одинаковые
    }
    
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        
        int n = this.value.length;
        if (n == anotherString.value.length) {
            // Сравниваем каждый символ
            char v1[] = this.value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

Да, содержимое одинаковое → true.

Сравнение s3 == s4false

Оба объекта созданы с new, каждый раз создаётся новый объект в Heap:

┌─────────────────────────┐
│       Heap (память)     │
├─────────────────────────┤
│   "Hello" (объект 2)   │◄─── s3
│   "Hello" (объект 3)   │◄─── s4
└─────────────────────────┘

Разные объекты = разные ссылки → false.

Сравнение s3.equals(s4)true

Оба объекта содержат одинаковый текст → true.

Что такое String Pool?

String Pool (также называемый String Intern Pool) — это специальная область памяти (часть Heap), где Java хранит уникальные строковые литералы.

String a = "Java";      // "Java" добавляется в pool
String b = "Java";      // Переиспользуется из pool
String c = new String("Java"); // Новый объект вне pool

System.out.println(a == b);  // true (одна ссылка из pool)
System.out.println(a == c);  // false (разные объекты)
System.out.println(a.equals(c)); // true (одинаковое содержимое)

Зачем нужен String Pool?

  • Оптимизация памяти — строки часто повторяются
  • Производительность — переиспользование экономит память
  • Сравнение== быстрее работает со ссылками

Различие между == и equals()

ОператорЧто сравниваетСкоростьИспользование
==Ссылки (адреса)Быстро O(1)Null-проверки, идентичность
equals()СодержимоеМедленнее O(n)Сравнение значений

Правильное сравнение строк

// ❌ НЕПРАВИЛЬНО — может вернуть false
if (userInput == "admin") {
    // Не будет работать!
}

// ✅ ПРАВИЛЬНО — сравнивает содержимое
if (userInput.equals("admin")) {
    // Правильно!
}

// ✅ ПРАВИЛЬНО — игнорирует регистр
if (userInput.equalsIgnoreCase("ADMIN")) {
    // Также правильно!
}

// ✅ ПРАВИЛЬНО — null-safe сравнение (Java 11+)
if (Objects.equals(userInput, "admin")) {
    // Не выбросит NullPointerException
}

Когда использовать что?

Используйте ==:

String s = null;

if (s == null) {  // ✅ Правильно
    System.out.println("Null!");
}

if (s.equals(null)) {  // ❌ NullPointerException!
    System.out.println("Null!");
}

Используйте equals():

String username = "john_doe";

if (username.equals("john_doe")) {  // ✅ Правильно
    System.out.println("Welcome!");
}

if (username == "john_doe") {  // ❌ Может быть false
    System.out.println("Welcome!");
}

Производительность

String s1 = "Hello World".intern();  // Добавить в pool
String s2 = new String("Hello World").intern();  // Получить из pool

long start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
    boolean result = s1 == s2;  // Очень быстро
}
long time1 = System.nanoTime() - start;

start = System.nanoTime();
for (int i = 0; i < 1_000_000; i++) {
    boolean result = s1.equals(s2);  // Медленнее
}
long time2 = System.nanoTime() - start;

System.out.println("== время: " + time1);
System.out.println("equals() время: " + time2);
// Обычно == примерно в 10 раз быстрее!

Метод intern()

String s1 = new String("Hello");
String s2 = "Hello";

System.out.println(s1 == s2);  // false

String s3 = s1.intern();  // Добавляем в String Pool
System.out.println(s3 == s2);  // true

Метод intern() добавляет строку в String Pool и возвращает ссылку на объект в pool.

Итоговые правила

  1. Для сравнения содержимого строк: используйте equals() или equalsIgnoreCase()
  2. Для проверки на null: используйте ==
  3. Для идентичности объектов: используйте ==
  4. Никогда не полагайтесь на == для сравнения строк (кроме null-проверок)
  5. Если производительность критична → используйте intern(), но с осторожностью
Сравнение строк: == vs equals() | PrepBro