Точная разница между CharSequence и String в java [дубликат]

этот вопрос уже есть ответ здесь:

  • CharSequence против строки в Java? 9 ответов
  • почему StringBuilder, когда есть строка? 10 ответов
  • выбор между CharSequence и String для API [дубликат] 1 ответ

Я прочитал это предыдущий пост. Может ли кто-нибудь сказать, какая точная разница между CharSequence и строка, кроме того, что String осуществляет CharSequence и String - это последовательность символов? Для пример:

CharSequence obj = "hello";
String str = "hello";
System.out.println("output is : " + obj + "  " + str);

что происходит, когда "привет" назначен obj и снова str ?

8 ответов


общие различия

есть несколько классов, которые реализуют CharSequence интерфейс кроме String. Среди них

  • StringBuilder для последовательностей символов переменной длины, которые могут быть изменены
  • CharBuffer для фиксированной длины низкоуровневых последовательностей символов, которые могут быть изменены

любой метод, который принимает CharSequence может работать на все это одинаково хорошо. Любой метод, который принимает только String потребует преобразования. Итак, используя CharSequence как тип аргумента во всех местах, где вы не заботитесь о внутренних органах, разумно. Однако, вы должны использовать String как тип возврата, если вы фактически возвращаете String, потому что это позволяет избежать возможных преобразований возвращаемых значений, если вызывающий метод действительно требует String.

Также обратите внимание, что карты должны использовать String как тип ключа, а не CharSequence, как карта ключи не должны меняться. Другими словами, иногда неизменная природа String имеет важное значение.

конкретный фрагмент кода

что касается кода, который вы вставили: просто скомпилируйте его и посмотрите на байт-код JVM, используя javap -v. Там вы заметите, что оба obj и str являются ссылками на один и тот же постоянный объект. Как String является неизменным, этот вид обмена в порядке.

на + оператор String компилируется как призывы различных StringBuilder.append звонки. Таким образом, это эквивалентно

System.out.println(
  (new StringBuilder())
  .append("output is : ")
  .append((Object)obj)
  .append(" ")
  .append(str)
  .toString()
)

я должен признаться, я немного удивлен, что мой компилятор javac 1.6.0_33 составляет + obj используя StringBuilder.append(Object) вместо StringBuilder.append(CharSequence). Первый, вероятно, включает в себя вызов toString() метод объекта, тогда как последний должен быть возможен более эффективным способом. С другой стороны,--26--> просто возвращает String сам, так что там мало штрафа. Так что StringBuilder.append(String) может быть более эффективным, о один метод вызова.


tl; dr

One-это интерфейс (CharSequence), а другой-конкретную реализацию этого интерфейса (String).

CharSequence animal = "cat"  // `String` object presented as the interface `CharSequence`.

как интерфейс, обычно CharSequence было бы более часто видно, чем String, но некоторая скрученная история привела к тому, что интерфейс был определен годами после реализация. Поэтому в более старых API мы часто видим String в то время как в новых API мы склонны видеть CharSequence используется для определения Аргументы и возвращаемые типы.

подробности

в настоящее время мы знаем, что обычно API/framework должен сосредоточиться на экспорте интерфейсов в первую очередь и конкретных классов во вторую очередь. Но мы не всегда так хорошо знали этот урок.

на String класс пришел первым в Java. Только позже они разместили фронтальный интерфейс,CharSequence.

Закрученная История

немного истории может помочь с пониманием.

In его первые дни Java был спешил на рынок немного раньше своего времени из-за Интернет/веб-мании, оживляющей отрасль. Некоторые библиотеки были не так хорошо продуманы, как следовало бы. Одной из таких областей была обработка строк.

кроме того, Java был одним из самых ранних ориентированных на производство неакадемических объектно-ориентированное программирование (ООП) средах. Единственными успешными реальными реализациями каучука-встреч-дороги ООП до этого были некоторые ограниченные версии SmallTalk, потом С С NeXTSTEP/OpenStep. Таким образом, многие практические уроки еще предстоит извлечь.

Java началась с String класс а StringBuffer класса. Но эти два класса не были связаны между собой, не были связаны друг с другом ни наследованием, ни интерфейсом. Позже команда Java признала, что должна была быть объединяющая связь между связанными строками реализации, чтобы сделать их взаимозаменяемыми. В Java 4 команда добавила CharSequence интерфейс и ретроактивно реализован этот интерфейс на String и String Buffer, а также добавление другой реализации CharBuffer. Позже, в Java 5 они добавили StringBuilder, в основном несинхронизированная и, следовательно, несколько более быстрая версия StringBuffer.

таким образом, эти строковые классы немного беспорядок, и немного запутанным, чтобы узнать о. Многие библиотеки и интерфейсы были созданы для take и return String объекты. В настоящее время такие библиотеки, как правило, должны быть построены ожидать CharSequence. Но (а)String кажется, все еще доминирует в пространстве разума, и (Б) могут быть некоторые тонкие технические проблемы при смешивании различных CharSequence реализаций. Оглядываясь назад, мы можем видеть, что все эти струнные вещи могли бы быть лучше обработаны, но вот мы здесь.

в идеале Java началась бы с интерфейс и / или суперкласс, который будет использоваться во многих местах, где мы сейчас используем String, так же, как мы используем Collection или List интерфейсы вместо ArrayList или LinkedList реализаций.

Интерфейс И Класс

ключевая разница о CharSequence - это интерфейс, а не реализация. Это означает, что вы не можете напрямую создать экземпляр CharSequence. Скорее вы создаете экземпляр одного из классов, который реализует этот интерфейс.

например, здесь мы имеем x вот такой CharSequence но под ним на самом деле


CharSequence договора (интерфейс), и String это реализация настоящего Договора.

public final class String extends Object 
    implements Serializable, Comparable<String>, CharSequence

на документация на CharSequence - это:

CharSequence-это читаемая последовательность значений char. Этот интерфейс обеспечивает равномерное, только для чтения доступ ко многим различным видам char последовательности. Значение char представляет символ в Basic Многоязычный самолет (BMP) или суррогат. См. Unicode Характер Представление для деталей.


кроме того, что строка реализует CharSequence и что строка является последовательностью символов.

некоторые вещи в коде:

CharSequence obj = "hello";

создает String буквальный, "hello", который является String "объект". Быть String, который реализует CharSequence, это CharSequence. (вы можете читать этот пост о кодировании в интерфейс например).

следующий строка:

String str = "hello";

немного сложнее. String литералы на Java хранятся в пуле (интернированы), поэтому "hello" в этой строке находится тот же объект (идентификатор), что и "hello" на первой линии. Поэтому эта строка присваивает только то же самое String литерал str.

в этот момент оба obj и str относятся к String литерал и equals, == и как String и a CharSequence.

предлагаю вам протестировать этот код, показав в действии то, что я только что написал:

public static void main(String[] args) {
    CharSequence obj = "hello";
    String str = "hello";
    System.out.println("Type of obj: " + obj.getClass().getSimpleName());
    System.out.println("Type of str: " + str.getClass().getSimpleName());
    System.out.println("Value of obj: " + obj);
    System.out.println("Value of str: " + str);
    System.out.println("Is obj a String? " + (obj instanceof String));
    System.out.println("Is obj a CharSequence? " + (obj instanceof CharSequence));
    System.out.println("Is str a String? " + (str instanceof String));
    System.out.println("Is str a CharSequence? " + (str instanceof CharSequence));
    System.out.println("Is \"hello\" a String? " + ("hello" instanceof String));
    System.out.println("Is \"hello\" a CharSequence? " + ("hello" instanceof CharSequence));
    System.out.println("str.equals(obj)? " + str.equals(obj));
    System.out.println("(str == obj)? " + (str == obj));
}

Я знаю, что это своего рода очевидно, но CharSequence-это интерфейс, тогда как String-конкретный класс:)

java.ленг.String является реализацией этого интерфейса...


рассмотрим UTF-8. В UTF-8 кодовые точки Unicode строятся из одного или нескольких байтов. Класс, инкапсулирующий массив байтов UTF-8, может реализовать интерфейс CharSequence, но, безусловно, не является строкой. Конечно, вы не можете передать массив байтов UTF-8, где ожидается строка, но вы, безусловно, можете передать класс оболочки UTF-8, который реализует CharSequence, когда контракт расслаблен, чтобы разрешить CharSequence. В моем проекте я разрабатываю класс под названием CBTF8Field (сжатая двоичная передача Формат-восемь бит), чтобы обеспечить сжатие данных для xml, и я хочу использовать интерфейс CharSequence для реализации преобразований из массивов байтов CBTF8 в/из символьных массивов (UTF-16) и байтовых массивов (UTF-8).

причина, по которой я пришел сюда, заключалась в том, чтобы получить полное представление о контракте подпоследовательности.


из API Java CharSequence:

CharSequence-это читаемая последовательность символов. Этот интерфейс обеспечивает единый доступ только для чтения ко многим различным типам последовательностей символов.

этот интерфейс затем используется строка, CharBuffer и StringBuffer чтобы сохранить согласованность для всех имен методов.


в charSequence у вас нет очень полезных методов, которые доступны для String. Если вы не хотите искать в документации, введите: параметр obj. и ул.

и посмотрите, какие методы предлагает вам ваш компилятор. Это основное различие для меня.