Снимите пальто и внимательно проанализируйте: почему String неизменяем

Java задняя часть

Мало знаний, большой вызов! Эта статья участвует в "Необходимые знания для программистов«Творческая деятельность

Говоря оJava исходный код, я считаю, что у моих друзей есть более или менее контакт, например, общий ArrayList, HashMap, LinkedHashMap в пакете util и классы, связанные с многопоточностью, которые мы изучили ранее, такие как:Executors,CountDownLatch,CyclicBarrier, или в пакете langObject,Integer,String,ThreadЖдать.

Это наши более распространенные классы, но иногда мы не можем сказать, почему они реализованы.Некоторые люди даже пишут код в течение четырех или пяти лет, и они даже не видели, как реализован самый распространенный String.Я всегда жалуюсь, что Я всегда передвигаю кирпичи каждый день, и мое будущее потеряно. Честно говоря, изучение исходного кода заключается не только в том, чтобы иметь дело с интервью, но, что более важно, в процессе чтения исходного кода,изучите его дизайн-мышление, эту идею можно полностью реализовать в нашем проекте.

Таким образом, чтение исходного кода имеет следующие преимущества:

  1. Научитесь отличным дизайнерским идеям;
  2. Увеличьте силу интервью и подметайте все;
  3. Напрягите мышцы во время ежедневных обзоров кода.

Во-вторых, анализ исходного кода String.

Сначала посмотрите на небольшой пример:

String name = "huage";
name="huasao";

Я полагаю, что мы также столкнемся с проблемами типа [в этом процессе несколько объектов] в интервью.На самом деле, когда имя будет переназначено, оно не будет изменено в исходном адресе памяти, а будет создан новый объект, как показано на следующем рисунке.

image.png

2.1 Ненаследуемая причина 1: определение класса

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
...
}

В приведенном выше примере нам нужно проанализировать из кода, почему String является неизменяемым, мы можем видеть в определении класса String.java: класс String изменен с помощью ключевого слова final, что также означает, что класс String не может быть унаследован, после создания , его нельзя изменить.

Класс String также реализует три интерфейса:

  • Сериализация: внедрение сериализации, отметьте интерфейс, который используется для идентификации сериализации и не может быть сериализован без реализации этого интерфейса.
  • Comparable: Сравните размер двух созданных объектов.
  • CharSequence: String по существу представляет собой массив символов, и этот интерфейс представляет собой последовательность символов, доступную только для чтения.

2.2 Ненаследуемая причина 2: переменные-члены

/** The value is used for character storage. */
private final char value[];

Данные, хранящиеся в String, представляют собой значение массива char, и значение также изменяется с помощью final, что означает, что массив нельзя изменить.

Но в это время некоторые друзья спросят: переменные, измененные final, являются неизменяемыми только по ссылке, а значение в куче памяти может быть полностью изменено.

final char value[] = {'h','u','a','g','e'};
value[4] = 's';
System.out.println(value); //最终输出:huags

В настоящее время мы должны взглянуть на это. сгенерировано.

2.3 Расширение: общие методы

Далее посмотрим, как реализованы несколько общих методов в классе String.

  • equals
public boolean equals(Object anObject) {
    //内存地址是否相同
    if (this == anObject) {
        return true;
    }
    //目标对象是否为String类,不是的话直接返回false
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        //判断两者长度是否相等
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            //比较两者中每一个字符是否相等
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
  • Строка перехвата: подстрока
public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > value.length) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    int subLen = endIndex - beginIndex;
    if (subLen < 0) {
        throw new StringIndexOutOfBoundsException(subLen);
    }
    return ((beginIndex == 0) && (endIndex == value.length)) ? this
            : new String(value, beginIndex, subLen);
}

Из приведенного выше исходного кода можно сделать вывод, что для начального/конечного индекса, который соответствует условиям, метод вызовет конструктор new String(), и конструктор, наконец, сгенерирует новую строку для возврата через System.arraycopy, которая означает, что этот метод не изменяет исходную строку.

Точно так же мы можем просмотреть исходный код таких методов, как replace и concat, Они не будут изменять исходную строку, но будут генерировать новый строковый объект для возврата, что также является неизменностью String.

Три, String неизменяемые преимущества

  • сохранить память

Если определено несколько объектов и значение каждого объекта одинаково, на практике в динамической памяти будет храниться только одна копия данных, что позволит сократить накладные расходы памяти.

image.png

\