Java中CharSequence和String之间的确切区别tl;博士详

2022-08-31 09:46:19

我读了上一篇文章。除了String实现了CharSequence并且是一个字符序列之外,还有谁能说出和String之间的确切区别吗?例如:CharSequenceString

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

当“hello”被分配给并再次分配给时会发生什么?objstr


答案 1

一般差异

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

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

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

特定代码片段

至于你粘贴的代码:只需编译它,并使用 查看JVM字节码。在那里,您会注意到两者和都是对同一常量对象的引用。作为不可变的,这种共享是可以的。javap -vobjstrString

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

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

我必须承认,我有点惊讶,我的编译器编译了 using 而不是 .前者可能涉及对对象方法的调用,而后者应该以更有效的方式实现。另一方面,简单地返回本身,所以几乎没有惩罚。因此,通过大约一个方法调用可能会更有效。javac 1.6.0_33+ objStringBuilder.append(Object)StringBuilder.append(CharSequence)toString()String.toString()StringStringBuilder.append(String)


答案 2

tl;博士

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

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

就像ArrayList是一个列表HashMap是一个Map一样,.StringCharSequence

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

如今,我们知道API/框架通常应该主要关注导出接口,其次是导出具体类。但是我们并不总是那么了解这个教训。

该课程在Java中排名第一。直到后来,他们才放置了一个面向前置的界面。StringCharSequence

扭曲的历史

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

在早期,Java被赶到市场上,由于互联网/Web狂热对这个行业产生了兴趣。一些图书馆没有像他们应该的那样经过深思熟虑。字符串处理是这些领域之一。

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

Java从String类和StringBuffer类开始。但这两个类是无关的,不是通过继承或接口相互绑定的。后来,Java团队认识到,在与字符串相关的实现之间应该有一个统一的联系,以使它们可互换。在Java 4中,该团队添加了CharSequence接口,并在String和String Buffer上追溯性地实现了该接口,并添加了另一个实现CharBuffer。后来在Java 5中,他们添加了StringBuilder,基本上是一个不同步的版本,因此速度更快。StringBuffer

因此,这些面向字符串的类有点混乱,学习起来有点混乱。许多库和接口都是为了获取和返回对象而构建的。如今,这些库通常应该按照预期进行构建。但是(a)似乎仍然主导着思维空间,(b)在混合各种实现时可能存在一些微妙的技术问题。有了事后看来的20/20愿景,我们可以看到所有这些字符串的东西本可以得到更好的处理,但是我们在这里。StringCharSequenceStringCharSequence

理想情况下,Java应该从一个接口和/或超类开始,这些接口和/或超类将在我们现在使用的许多地方使用,就像我们使用集合列表接口来代替ArrayListLinkedList实现一样。String

接口与类

关键区别在于它是一个接口,而不是一个实现。这意味着您无法直接实例化 .相反,您可以实例化实现该接口的类之一。CharSequenceCharSequence

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

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的版本,其中它们似乎展示了这些类和接口发生了多大的变化。

diagram showing the various string-related classes and interfaces as of Java 8

文本块

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

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

引用JEP 378:

文本块是一种多行字符串文本,它避免了对大多数转义序列的需求,以可预测的方式自动设置字符串的格式,并在需要时使开发人员能够控制格式。

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

示例

再次引用JSR 378...

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

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";
               """;

文本块在 Java 15 及更高版本中,根据 JEP 378:文本块

在 Java 13 中首次预览,在 JEP 355 下:文本块(预览版)下。然后在 Java 14 中在 JEP 368:文本块(第二次预览)下再次预览。

这项工作之前是JEP 326:原始字符串文本(预览版)。这些概念被重新设计为产生文本块功能。