Точная разница между CharSequence и String в java
Я прочитал этот предыдущий пост. Может ли кто-нибудь сказать, что такое точная разница между CharSequence
и String, кроме того, что String
реализует CharSequence
и что String
- это последовательность символов? Например:
CharSequence obj = "hello";
String str = "hello";
System.out.println("output is : " + obj + " " + str);
Что происходит, когда "привет" назначается obj
и снова на str
?
Ответы
Ответ 1
Общие отличия
Существует несколько классов, которые реализуют интерфейс 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()
объекта, тогда как последнее должно быть возможным более эффективным способом. С другой стороны, String.toString()
просто возвращает сам String
, поэтому там немного штрафа. Таким образом, StringBuilder.append(String)
может быть более эффективным примерно одним вызовом метода.
Ответ 2
ТЛ; др
Один - это интерфейс ( CharSequence
), а другой - конкретная реализация этого интерфейса ( String
).
CharSequence animal = "cat" // 'String' object presented as the interface 'CharSequence'.
Как интерфейс, обычно CharSequence
можно увидеть чаще, чем String
, но некоторая искаженная история привела к тому, что интерфейс определялся спустя годы после реализации. Поэтому в старых API мы часто видим String
а в более новых API мы склонны видеть CharSequence
используемый для определения аргументов и возвращаемых типов.
подробности
В настоящее время мы знаем, что обычно API/framework должны фокусироваться на экспорте интерфейсов в первую очередь и конкретных классов во вторую очередь. Но мы не всегда знали этот урок так хорошо.
Класс String
появился первым на Java. Только позже они разместили интерфейс, CharSequence
на передней панели, CharSequence
.
Искаженная история
Немного истории может помочь с пониманием.
В первые дни Java была спешно выпущена на рынок немного раньше времени из-за мании интернета/Интернета, оживляющего индустрию. Некоторые библиотеки были не так хорошо продуманы, как следовало бы. Обработка строк была одной из тех областей.
Кроме того, Java была одной из первых производственных ориентированных неакадемических объектно-ориентированных программ (ООП). Единственными успешными реальными реализациями OOP, отвечающими требованиям реального времени, были некоторые ограниченные версии SmallTalk, а затем Objective-C с NeXTSTEP/OpenStep. Таким образом, многие практические уроки еще предстоит выучить.
Java началась с класса String
класса StringBuffer
. Но эти два класса не были связаны, не связаны друг с другом ни наследованием, ни интерфейсом. Позже, команда Java поняла, что должна быть объединяющая связь между реализациями, связанными со строками, чтобы сделать их взаимозаменяемыми. В Java 4 команда добавила интерфейс CharSequence
и задним числом реализовала этот интерфейс в String и String Buffer, а также добавила еще одну реализацию CharBuffer
. Позже в Java 5 они добавили StringBuilder
, в основном несинхронизированную и, следовательно, несколько более быструю версию StringBuffer
.
Таким образом, эти классы, ориентированные на строки, немного беспорядочные и немного запутанные для изучения. Многие библиотеки и интерфейсы были созданы для получения и возврата объектов String
. В настоящее время такие библиотеки должны быть построены так, чтобы ожидать CharSequence
. Но (a) String
похоже, все еще доминирует в пространстве ума, и (b) могут возникнуть некоторые тонкие технические проблемы при смешивании различных реализаций CharSequence
. С учетом ретроспективного взгляда 20/20 мы видим, что со всеми этими струнными вещами можно было бы справиться лучше, но мы здесь.
В идеале Java должна начинаться с интерфейса и/или суперкласса, который будет использоваться во многих местах, где мы сейчас используем String
, так же, как мы используем интерфейсы Collection
или List
вместо реализаций ArrayList
или LinkedList
.
Интерфейс против класса
Главное отличие CharSequence
том, что это интерфейс, а не реализация. Это означает, что вы не можете напрямую создать экземпляр CharSequence
. Скорее вы создаете экземпляр одного из классов, который реализует этот интерфейс.
Например, здесь мы имеем x
, который выглядит как CharSequence
но внизу на самом деле является StringBuilder
объектом.
CharSequence x = new StringBuilder( "dog" );
Это становится менее очевидным при использовании строкового литерала. Помните, что когда вы видите исходный код с кавычками вокруг символов, компилятор преобразует его в объект String.
CharSequence y = "cat"; // Looks like a CharSequence but is actually a String instance.
Есть некоторые тонкие различия между "cat"
и new String("cat")
как обсуждалось в этом другом вопросе, но здесь они не имеют значения.
Диаграмма классов
Эта диаграмма классов может помочь вам. Я отметил версию Java, в которой они появились, чтобы продемонстрировать, насколько много изменений произошло в этих классах и интерфейсах.
![diagram showing the various string-related classes and interfaces as of Java 8]()
Текстовые блоки
За исключением все большего количества смайликов и других персонажей, которые приходят с последовательными версиями поддержки Unicode, в последние годы в Java мало что изменилось для работы с текстом... до Java 13.
Java 13 может предлагать предварительный просмотр новой функции: текстовые блоки. Это сделает написание строк встроенного кода, такого как SQL, более удобным. Смотри JEP 355.
Этому усилию предшествовал JEP 326: Необработанные строковые литералы (превью).
Ответ 3
CharSequence
является контрактом (interface), а String
является implementation этого договора.
public final class String extends Object
implements Serializable, Comparable<String>, CharSequence
документация для CharSequence
:
CharSequence является читаемой последовательностью значений char. Этот интерфейс обеспечивает единообразный доступ только для чтения к различным типам charпоследовательности. Значение char представляет символ в Basic Многоязычный самолет (BMP) или суррогат. Обратитесь к символу Unicode Представление для деталей.
Ответ 4
кроме того, что String реализует CharSequence и что String является последовательностью символов.
В коде есть несколько вещей:
CharSequence obj = "hello";
Это создает литерал String
, "hello"
, который является объектом String
. Будучи String
, который реализует CharSequence
, он также является CharSequence
. (вы можете прочитать этот пост о кодировании для интерфейса).
Следующая строка:
String str = "hello";
немного сложнее. String
литералы в Java хранятся в пуле (интернированном), поэтому "hello"
в этой строке является одним и тем же объектом (идентификатором) как "hello"
в первой строке. Поэтому эта строка присваивает только тегу String
для str
.
В этот момент оба obj
и str
являются ссылками на String
литерал "hello"
и поэтому 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));
}
Ответ 5
Я знаю это как нечто очевидное, но CharSequence - это интерфейс, тогда как String - это конкретный класс:)
java.lang.String - это реализация этого интерфейса...
Ответ 6
Рассмотрим UTF-8. В UTF-8 кодовые точки Юникода построены из одного или нескольких байтов. Класс, инкапсулирующий массив байтов UTF-8, может реализовать интерфейс CharSequence, но наиболее определенно не является строкой. Конечно, вы не можете передать массив байтов UTF-8, где ожидается String, но вы, безусловно, можете передать класс оболочки UTF-8, который реализует CharSequence, когда контракт ослаблен, чтобы разрешить CharSequence. В моем проекте я разрабатываю класс под названием CBTF8Field (сжатый двоичный формат передачи - восемь бит) для обеспечения сжатия данных для xml и я хочу использовать интерфейс CharSequence для реализации преобразований из массивов байтов CBTF8 в/из массивов символов (UTF-16 ) и байтовые массивы (UTF-8).
Я пришел сюда, чтобы получить полное представление о контракте подпоследовательности.
Ответ 7
Из API Java CharSequence:
CharSequence - это читаемая последовательность символов. Этот интерфейс обеспечивает единообразный доступ только для чтения ко многим различным типам последовательностей символов.
Этот интерфейс затем используется String, CharBuffer и StringBuffer, чтобы сохранить согласованность для всех имен методов.
Ответ 8
В charSequence у вас нет очень полезных методов, доступных для String. Если вы не хотите просматривать документацию, введите: OBJ.
а также ул.
и посмотрите, какие методы предлагает ваш компилятор. Это основное отличие для меня.