106

我读过这篇以前的帖子。谁能说出CharSequence和 String 之间的确切区别是什么,除了String实现CharSequence和那String是一个字符序列的事实吗?例如:

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

当“你好”被分配给obj并再次分配给时会发生什么str

4

8 回答 8

104

一般差异

除了 之外,还有几个实现CharSequence接口的类String。其中有

  • StringBuilder对于可以修改的可变长度字符序列
  • CharBuffer用于可以修改的固定长度的低级字符序列

任何接受 a 的方法CharSequence都可以同样好地操作所有这些。任何只接受 a 的方法String都需要转换。因此CharSequence,在您不关心内部结构的所有地方使用作为参数类型是谨慎的。但是,如果您实际返回 a ,则应将String其用作返回类型String,因为如果调用方法确实需要 a ,则可以避免可能的返回值转换String

另请注意,映射应用String作键类型,而不是CharSequence,因为映射键不得更改。换句话说,有时不可变的性质String是必不可少的。

具体代码片段

至于您粘贴的代码:只需编译它,然后使用javap -v. 在那里你会注意到两者objstr都是对同一个常量对象的引用。由于 aString是不可变的,所以这种共享是可以的。

+运算符String被编译为各种调用的StringBuilder.append调用。所以它相当于

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

我必须承认,我的编译器javac 1.6.0_33编译的是+ objusingStringBuilder.append(Object)而不是StringBuilder.append(CharSequence). 前者可能涉及toString()对对象方法的调用,而后者应该以更有效的方式成为可能。另一方面,String.toString()简单地返回String自身,所以那里几乎没有惩罚。因此 StringBuilder.append(String),通过大约一种方法调用可能会更有效。

于 2012-07-04T07:07:30.607 回答
92

tl;博士

一个是接口 ( CharSequence),而另一个是该接口 ( ) 的具体实现String

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

就像ArrayListis aListHashMapis a一样Map, aString也是CharSequence

作为一个接口,通常CharSequence会比 更常见String,但一些扭曲的历史导致接口在实现多年后被定义。因此,在较旧的 API 中我们经常看到String,而在较新的 API 中,我们倾向于看到CharSequence用于定义参数和返回类型。

细节

现在我们知道,API/框架通常应该主要关注导出接口,其次才是具体的类。但我们并不总是那么清楚这一课。

该类String首先出现在 Java 中。直到后来他们才放置了一个前置接口,CharSequence.

扭曲的历史

一点历史可能有助于理解。

在早期,由于 Internet/Web 狂热激发了整个行业的活力,Java 的上市时间稍早了一些。有些图书馆没有像他们应该做的那样深思熟虑。字符串处理就是这些领域之一。

此外,Java 是最早的面向生产的非学术面向对象编程 (OOP)环境之一。在此之前,OOP 的唯一成功的现实世界橡胶与道路的实现是SmallTalk的一些有限版本,然后是带有NeXTSTEP / OpenStep的 Objective-C。因此,许多实际的经验教训尚待学习。

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,就像我们使用CollectionorList接口代替ArrayListorLinkedList实现一样。

接口与类

关键区别CharSequence在于它是一个接口,而不是一个实现。这意味着您不能直接实例化一个CharSequence. 而是实例化实现该接口的类之一。

例如,这里我们有x一个看起来像 aCharSequence但下面实际上是一个StringBuilder对象。

CharSequence x = new StringBuilder( "dog" );  // Looks like a `CharSequence` but is actually a `StringBuilder` instance.

这在使用字符串文字时变得不那么明显了。请记住,当您看到仅在字符周围带有引号的源代码时,编译器会将其转换为 String 对象。

CharSequence y = "cat";  // Looks like a `CharSequence` but is actually a `String` instance.

文字与构造函数

之间有一些细微的区别"cat",正如另一个问题new String("cat")中所讨论的那样,但在这里无关紧要。

类图

这个类图可能有助于指导你。我注意到了 Java 版本,他们似乎在其中展示了通过这些类和接口发生了多少变化。

从 Java 8 开始,各种与字符串相关的类和接口的图表

文本块

除了添加更多Unicode字符(包括大量emoji )之外,近年来 Java 在处理文本方面并没有太大变化。直到文本块

文本块是一种更好地处理多行或字符转义的乏味字符串文字的新方法。这将使编写嵌入式代码字符串(如 HTML、XML、SQL 或 JSON)更加方便。

引用JEP 378

文本块是一个多行字符串文字,它避免了大多数转义序列的需要,以可预测的方式自动格式化字符串,并在需要时让开发人员控制格式。

文本块功能没有引入新的数据类型。文本块只是一种用于编写String文字的新语法。一个文本块产生一个String对象,就像传统的文字语法一样。如上所述,文本块产生一个String对象,该对象也是一个对象。CharSequence

SQL 示例

再次引用 JSR 378……</p>

使用“一维”字符串文字。

String query = "SELECT \"EMP_ID\", \"LAST_NAME\" FROM \"EMPLOYEE_TB\"\n" +
               "WHERE \"CITY\" = 'INDIANAPOLIS'\n" +
               "ORDER BY \"EMP_ID\", \"LAST_NAME\";\n";

使用“二维”文本块

String query = """
               SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
               WHERE "CITY" = 'INDIANAPOLIS'
               ORDER BY "EMP_ID", "LAST_NAME";
               """;

根据JEP 378: Text Blocks可以在Java 15及更高版本中找到文本块。

在 Java 13 中首次预览,在JEP 355: Text Blocks (Preview)下。然后在JEP 368: Text Blocks (Second Preview)下再次在 Java 14 中预览。

这项工作之前是JEP 326: Raw String Literals (Preview)。这些概念被重新设计以产生文本块功能。

于 2014-10-22T01:18:47.693 回答
22

CharSequence是一个契约(接口),并且String是这个契约的一个实现

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

文档CharSequence

CharSequence 是一个可读的 char 值序列。此接口提供对许多不同类型的字符序列的统一只读访问。char 值表示基本多语言平面 (BMP) 中的字符或代理项。有关详细信息,请参阅 Unicode 字符表示。

于 2012-07-04T07:10:02.957 回答
12

除了 String 实现 CharSequence 并且 String 是一个字符序列这一事实之外。

您的代码中发生了几件事:

CharSequence obj = "hello";

这会创建一个String字面"hello"量 ,它是一个String对象。作为一个String,它实现CharSequence,它也是一个CharSequence。(例如,您可以阅读这篇关于接口编码的文章)。

下一行:

String str = "hello";

稍微复杂一点。StringJava 中的文字保存在一个池中(实习),因此这一行上的 与第一行上的"hello"对象(身份)相同。"hello"因此,此行仅将相同的String文字分配给str.

在这一点上,两者objstr都是对String文字的引用,"hello"因此是equals==它们都是 aString和 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));
}
于 2012-07-04T07:42:50.913 回答
3

我知道这很明显,但是 CharSequence 是一个接口,而 String 是一个具体的类:)

java.lang.String 是这个接口的一个实现......

于 2012-07-04T07:03:01.843 回答
2

来自CharSequence的 Java API :

CharSequence 是一个可读的字符序列。该接口提供对许多不同类型的字符序列的统一的只读访问。

然后StringCharBufferStringBuffer使用该接口来保持所有方法名称的一致性。

于 2012-07-04T07:06:45.173 回答
2

考虑 UTF-8。在 UTF-8 中,Unicode 代码点由一个或多个字节构成。封装 UTF-8 字节数组的类可以实现 CharSequence 接口,但绝对不是字符串。当然,您不能在需要 String 的地方传递 UTF-8 字节数组,但是当合同放宽以允许 CharSequence 时,您当然可以传递实现 CharSequence 的 UTF-8 包装类。在我的项目中,我正在开发一个名为 CBTF8Field(压缩二进制传输格式 - 八位)的类来为 xml 提供数据压缩,并希望使用 CharSequence 接口来实现从 CBTF8 字节数组到字符数组(UTF-16 ) 和字节数组 (UTF-8)。

我来这里的原因是为了对子序列合约有一个完整的了解。

于 2013-09-20T19:10:16.407 回答
1

在 charSequence 中,您没有可用于 String 的非常有用的方法。如果您不想查看文档,请键入:obj。和海峡。

并查看您的编译器为您提供了哪些方法。这就是我的基本区别。

于 2012-07-04T07:10:07.667 回答