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

Какая разница между объектами класса String и других классов?

1.0 Junior🔥 191 комментариев
#Основы Java

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

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

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

Разница между String и другими классами в Java

String — это особый класс в Java, который получает специальное обращение от JVM. Рассмотрю все отличия: от внутреннего устройства до практических примеров.

Основное отличие: String immutable (неизменяемый)

public class StringImmutabilityExample {
    public static void main(String[] args) {
        // String
        String str1 = "Hello";
        String str2 = str1.concat(" World");
        
        System.out.println("str1: " + str1);  // Hello (не изменился)
        System.out.println("str2: " + str2);  // Hello World (новый объект)
        System.out.println("str1 == str2: " + (str1 == str2));  // false
        
        // Обычный класс (mutable - изменяемый)
        StringBuilder sb = new StringBuilder("Hello");
        StringBuilder sb2 = sb.append(" World");
        
        System.out.println("sb: " + sb);   // Hello World (изменился)
        System.out.println("sb == sb2: " + (sb == sb2));  // true (один объект)
    }
}

Ключевое правило: String не может быть изменён, любая операция создаёт новый объект.

String Pool (String интернирование)

Это уникальная особенность String класса:

public class StringPoolExample {
    public static void main(String[] args) {
        // Создание через литерал (в String Pool)
        String str1 = "Hello";
        String str2 = "Hello";
        
        // Обе переменные ссылаются на ОДИН объект в памяти
        System.out.println("str1 == str2: " + (str1 == str2));  // true
        System.out.println("str1.equals(str2): " + str1.equals(str2));  // true
        
        // Создание через new (в heap, не в Pool)
        String str3 = new String("Hello");
        String str4 = new String("Hello");
        
        // Разные объекты в heap
        System.out.println("str3 == str4: " + (str3 == str4));  // false
        System.out.println("str3.equals(str4): " + str3.equals(str4));  // true
        
        // Но str1 и str3 имеют одинаковое значение
        System.out.println("str1 == str3: " + (str1 == str3));  // false (разные объекты)
        System.out.println("str1.equals(str3): " + str1.equals(str3));  // true
    }
}

Внутреннее представление String

public class StringInternalStructure {
    public static void main(String[] args) {
        // Java 9+: String хранит данные как byte[], а не char[]
        String str = "Hello";
        
        // До Java 9 (char[] внутри):
        // private final char[] value;
        // Размер: каждый char = 2 байта
        // "Hello" = 5 * 2 = 10 байт
        
        // Java 9+ (byte[] с encoding flag):
        // private final byte[] value;
        // private final byte coder;  // 0 = LATIN1, 1 = UTF16
        // "Hello" = 5 * 1 = 5 байт (LATIN1 encoding)
        
        System.out.println("Объект String содержит:");        
        // Object Header: 16 байт
        // Ссылка на массив: 8 байт
        // hash field: 4 байта
        // Padding: 4 байта
        // + данные массива
    }
}

Неизменяемость (Immutability)

public final class String extends Object
{
    // private final byte[] value;
    // private int hash;
    // String класс final - НЕЛЬЗЯ наследовать
    // Все поля final - НЕЛЬЗЯ изменить
    // Нет setter методов
}

public class StringImmutabilityBenefits {
    
    // Преимущество 1: Thread Safety
    public static void threadSafetyExample() {
        String str = "Hello";  // Immutable
        // Много потоков могут безопасно читать одновременно
        // Нет race conditions
    }
    
    // Преимущество 2: HashMap безопасность
    public static void hashMapExample() {
        Map<String, Integer> map = new HashMap<>();
        String key = "user1";
        
        map.put(key, 100);
        
        // String immutable, поэтому поиск всегда работает
        Integer value = map.get("user1");
    }
}

Сравнение с другими классами

public class ComparisonWithOtherClasses {
    
    // StringBuilder - MUTABLE (изменяемый)
    public static void stringBuilderExample() {
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" World");
        sb.append("!");
        
        // Один объект, 3 операции, хороша для конкатенации
        String result = sb.toString();
        System.out.println(result);  // Hello World!
    }
    
    // StringBuffer - MUTABLE + SYNCHRONIZED
    public static void stringBufferExample() {
        // StringBuffer = StringBuilder, но thread-safe
        StringBuffer sb = new StringBuffer();
        // Медленнее из-за синхронизации
    }
    
    // Обычный класс - MUTABLE
    public static class User {
        private String name;  // immutable field
        private int age;      // mutable field
        
        public void setAge(int age) {
            this.age = age;  // можно изменить
        }
    }
}

Практические примеры

Проблема 1: String конкатенация

public class StringConcatenationProblem {
    
    // МЕДЛЕННО: создаёт 1000 временных объектов
    public static String slowConcat(String[] words) {
        String result = "";
        for (String word : words) {
            result += word;  // Каждый раз новый объект
        }
        // Временная сложность: O(n²)
        return result;
    }
    
    // БЫСТРО: переиспользует StringBuilder
    public static String fastConcat(String[] words) {
        StringBuilder sb = new StringBuilder();
        for (String word : words) {
            sb.append(word);  // Один объект
        }
        // Временная сложность: O(n)
        return sb.toString();
    }
    
    public static void main(String[] args) {
        String[] words = new String[10000];
        for (int i = 0; i < words.length; i++) {
            words[i] = "word";
        }
        
        long start = System.currentTimeMillis();
        String slow = slowConcat(words);
        System.out.println("Slow: " + (System.currentTimeMillis() - start) + "ms");
        
        start = System.currentTimeMillis();
        String fast = fastConcat(words);
        System.out.println("Fast: " + (System.currentTimeMillis() - start) + "ms");
    }
}

Проблема 2: Сравнение String

public class StringComparisonProblem {
    
    public static void main(String[] args) {
        // НЕПРАВИЛЬНО: используем ==
        String str1 = new String("hello");
        String str2 = new String("hello");
        
        if (str1 == str2) {  // false! (разные объекты)
            System.out.println("Равны");
        } else {
            System.out.println("Не равны");
        }
        
        // ПРАВИЛЬНО: используем equals()
        if (str1.equals(str2)) {  // true! (одинаковое содержимое)
            System.out.println("Равны");
        }
        
        // ПРАВИЛЬНО для регистронезависимого сравнения
        if (str1.equalsIgnoreCase("HELLO")) {  // true
            System.out.println("Равны без учёта регистра");
        }
    }
}

Важные различия

String: Immutable, Thread-safe, String Pool поддержка, медленная конкатенация StringBuilder: Mutable, НЕ thread-safe, БЕЗ String Pool, быстрая конкатенация Обычные классы: Обычно Mutable, зависит от реализации

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

Усе String для:

  • Данных, которые не меняются
  • Ключей HashMap
  • Многопоточных приложений
  • Когда нужна thread-safety

Используй StringBuilder для:

  • Конкатенации в циклах
  • Построения больших строк
  • Когда производительность критична

Не делай:

  • Конкатенацию String в циклах (+=)
  • Используй == для сравнения строк (используй equals())
  • Не полагайся на intern() без необходимости
String — это оптимизированный класс, который JVM особым образом поддерживает для производительности и безопасности в многопоточной среде!