String
实现CharSequence
并且String
是一个字符序列之外,有没有人能说出CharSequence
和String之间的确切区别?例如:CharSequence obj = "hello";
String str = "hello";
System.out.println("output is : " + obj + " " + str);
当将“hello”分配给
obj
,然后再次分配给 str
时会发生什么?String
实现CharSequence
并且String
是一个字符序列之外,有没有人能说出CharSequence
和String之间的确切区别?例如:CharSequence obj = "hello";
String str = "hello";
System.out.println("output is : " + obj + " " + str);
obj
,然后再次分配给 str
时会发生什么?除了 String
之外,还有几个实现了 CharSequence
接口的类。其中包括:
StringBuilder
,用于可变长度的字符序列,可进行修改CharBuffer
,用于固定长度的低级别字符序列,可进行修改任何接受 CharSequence
的方法都可以同样适用于上述所有类型。只有接受 String
的方法需要进行转换。因此,在不关心内部细节的所有地方使用 CharSequence
作为参数类型是明智的。但是,如果您实际上返回一个 String
,则应将其用作返回类型,因为这样可以避免在调用方法实际需要 String
的情况下对返回值进行转换。
还要注意,地图应该使用 String
作为键类型,而不是 CharSequence
,因为地图键不能更改。换句话说,有时不可变的特性对于 String
是必需的。
至于您贴出的代码:只需编译它,并使用 javap -v
查看 JVM 字节码。您会注意到,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()
只是返回字符串本身,因此几乎没有什么损失。因此,StringBuilder.append(String)
可能会更有效率,因为少了一个方法调用。
CharSequence
),而另一个是该接口的具体实现(String
)。CharSequence animal = "cat" // `String` object presented as the interface `CharSequence`.
ArrayList
是一个 List
,而 HashMap
是一个 Map
,同样地,String
是一个 CharSequence
。CharSequence
而不是 String
,但是由于一些扭曲的历史原因,这个接口在实现之后的几年才被定义。所以在旧的 API 中我们经常看到 String
,而在新的 API 中我们更倾向于使用 CharSequence
来定义参数和返回类型。
String
类和StringBuffer
类开始。但是这两个类没有关联,它们之间没有继承关系,也没有接口关系。后来,Java团队意识到在与字符串相关的实现之间应该有一个统一的联系,使它们可以互换使用。在Java 4中,团队添加了CharSequence
接口,并在String和String Buffer上实现了该接口,同时添加了另一个实现CharBuffer
。后来在Java 5中,他们添加了StringBuilder
,它基本上是StringBuffer
的非同步版本,因此速度更快一些。String
的许多地方都可以使用,就像我们在Collection
或List
接口代替ArrayList
或LinkedList
实现的地方一样。CharSequence
是一个接口,而不是一个实现。这意味着你不能直接实例化一个CharSequence
,而是实例化实现该接口的类之一。CharSequence x = new StringBuilder( "dog" ); // Looks like a `CharSequence` but is actually a `StringBuilder` instance.
CharSequence y = "cat"; // Looks like a `CharSequence` but is actually a `String` instance.
关于"cat"
和new String("cat")
之间有一些微妙的区别,可以在这个其他问题中讨论,但在这里并不重要。
这个类图可能会对你有所帮助。我标注了它们出现的Java版本,以展示这些类和接口经历了多少变化。
除了添加更多的Unicode字符,包括大量的表情符号,近年来在处理文本方面,Java并没有发生太多变化。直到出现了文本块。
文本块是一种更好地处理多行字符串字面量或字符转义的新方法。这将使编写嵌入式代码字符串(如HTML、XML、SQL或JSON)更加方便。
引用JEP 378的话:
文本块功能并没有引入新的数据类型。文本块只是一种用于编写文本块是一个多行字符串字面量,避免了大多数转义序列的需要,自动以可预测的方式格式化字符串,并在需要时给开发人员对格式的控制。
String
字面量的新语法。文本块生成一个String
对象,就像传统的字面量语法一样。文本块生成一个String
对象,该对象也是一个CharSequence
对象,如上所述。
再次引用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及更高版本中找到,参见Java 15和JEP 378: 文本块。
首次在Java 13中进行了预览,参见JEP 355: 文本块(预览)。然后在Java 14中再次进行了预览,参见JEP 368: 文本块(第二次预览)。
这项工作之前是JEP 326: 原始字符串字面量(预览)。这些概念经过重新设计,形成了文本块功能。
字符串模板通过将文字文本与嵌入式表达式和模板处理器相结合,产生特定的结果,以补充Java现有的字符串字面量和文本块。
查看JEP 430: 字符串模板(预览版)。CharSequence
是一个契约(interface),而 String
是这个契约的一个 implementation。
public final class String extends Object
implements Serializable, Comparable<String>, CharSequence
documentation中CharSequence
的内容如下:
CharSequence
是一个可读的char值序列。该接口提供了对许多不同类型的char序列的统一只读访问。char值表示基本多文种平面(BMP)中的字符或代理项。有关详细信息,请参阅Unicode字符表示。
除了String实现CharSequence接口并且String是字符序列外,你的代码中还发生了几件事情。
CharSequence obj = "hello";
这创建了一个String
文字,即"hello"
,它是一个String
对象。作为一个String
,它实现了CharSequence
接口,因此也是一个CharSequence
。(例如,您可以阅读这篇有关在Java中编写接口的文章)。
下一行:
String str = "hello";
这里稍微复杂了一些。在Java中,String
文字字符串会被存储在一个池子里(即被interned),因此这行代码上的"hello"
和第一行上的"hello"
是同一个对象(identity)。因此,这行代码只是将相同的String
文字字符串赋给了str
。
此时,obj
和str
都是指向"hello"
这个String
文字字符串的引用,因此它们equals
,==
,并且它们都是String
和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.lang.String是该接口的实现...
CharSequence是一个可读的字符序列。该接口提供了对许多不同类型的字符序列的统一只读访问。
然后,String, CharBuffer和StringBuffer使用此接口保持所有方法名称的一致性。
src.zip
的文件,其中包含了大部分的源代码。查看这些代码是可能且有用的,不过根据许可证的规定,修改它们可能涉及其他问题。 - MvG