在java中CharSequence和String之间的确切区别

我读过这个以前的post 。 任何人都可以说什么CharSequence和String之间的确切区别是什么,而不是String实现CharSequence的事实,而String是一个字符序列? 例如:

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

将“hello”分配给obj并再次分配给str时会发生什么?

一般差异

String之外,还有几个实现CharSequence接口的类。 这些之中

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

任何接受CharSequence都可以在所有这些CharSequence上运行。 任何只接受String都需要转换。 所以在所有你不关心内部的地方使用CharSequence作为参数types是谨慎的。 但是,如果实际返回一个String ,则应该使用String作为返回types,因为如果调用方法实际上确实需要一个String ,则可以避免返回值的可能转换。

还要注意地图应该使用String作为键types,而不是CharSequence ,因为地图键不能改变。 换句话说,有时String的不可变性质是必不可less的。

特定的代码片段

至于你粘贴的代码:简单地编译,并使用javap -v查看JVM字节码。 在那里你会注意到objstr都是对同一个常量对象的引用。 由于String是不可变的,所以这种分享是可以的。

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

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

我必须承认我有点惊讶,我的编译器javac 1.6.0_33使用StringBuilder.append(Object)而不是StringBuilder.append(CharSequence)编译+ obj 。 前者可能涉及对象的toString()方法的调用,而后者应该可以以更有效的方式进行。 另一方面, String.toString()只是返回String本身,所以在这里没有什么惩罚。 所以StringBuilder.append(String)在一个方法调用中可能更有效率。

TL;博士

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

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

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

细节

现在我们知道,API /框架通常应该主要侧重于导出接口,其次是具体类。 但是我们并不总是很清楚这个教训。

在Java中, String类首先出现了。 只是后来他们放置了一个前端界面, CharSequence

扭曲的历史

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

在成立初期,由于互联网/networking躁狂使这个行业蓬勃发展,Java被赶上了一些时间。 一些图书馆没有像应该做的那样精心devise。 string处理是其中的一个领域。

此外,Java是最早的面向生产的非学术型面向对象编程(OOP)环境之一。 在此之前,唯一成功的现实世界中的OOP实现是SmallTalk ,然后是Objective-C和NeXTSTEP / OpenStep 。 所以,许多实际的教训还有待学习。

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

所以这些面向string的类有点混乱,有点让人费解。 构build了许多库和接口来获取和返回String对象。 现在这样的图书馆一般应该build立期望CharSequence 。 但是(a) String似乎仍然主导着思维空间,并且(b)在混合各种CharSequence实现时可能存在一些细微的技术问题。 用20/20事后的看法,我们可以看到,所有这些string的东西本来可以被更好的处理,但在这里,我们是。

理想情况下,Java将从一个接口和/或超类开始,在我们现在使用String许多地方使用它,就像我们使用CollectionList接口代替ArrayListLinkedList实现一样。

界面与类

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

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

 CharSequence x = new StringBuilder( "dog" ); 

使用String文字时,这变得不那么明显了。 请记住,当你看到只带有引号的源代码时,编译器正在将它转换成一个String对象。

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

在另一个问题中讨论的"cat"new String("cat")之间有一些细微的差别,但在这里是不相关的。

类图

这个class级图可能有助于指导你。 我注意到Java的版本,他们似乎展示了通过这些类和接口搅动了多less变化。

该图显示了Java 8以来各种与字符串相关的类和接口

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

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

CharSequence的文档是:

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

除了String实现CharSequence的事实以外,String是一个字符序列。

在你的代码中发生了几件事情:

 CharSequence obj = "hello"; 

这会创build一个String "hello" ,它是一个String对象。 作为一个实现CharSequenceString ,它也是一个CharSequence 。 (你可以阅读这个关于编码接口的post )。

下一行:

 String str = "hello"; 

稍微复杂一点。 Java中的String文字被保存在一个池中,因此这一行上的"hello"与第一行中的"hello"是同一个对象(标识符)。 因此,这一行只将相同的String文字分配给str

在这一点上, objstr都是对String文字"hello"引用,因此是equals== ,它们都是一个String和一个CharSequence

我build议你testing这个代码,在行动中显示我刚刚写的:

 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是这个接口的实现…

考虑UTF-8。 在UTF-8中,Unicode代码点由一个或多个字节构成。 封装一个UTF-8字节数组的类可以实现CharSequence接口,但是绝对不是一个String。 当然,你不能传递一个UTF-8字节数组,当你想要一个string时,你肯定可以传递一个UTF-8封装类来实现CharSequence。 在我的项目中,我正在开发一个名为CBTF8Field(压缩二进制传输格式 – 八位)的类来为xml提供数据压缩,并且正在寻找使用CharSequence接口来实现从CBTF8字节数组到字符数组的转换(UTF-16 )和字节数组(UTF-8)。

我来到这里的原因是要完整理解后续合同。

从CharSequence的Java API:

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

这个接口被String , CharBuffer和StringBuffer用来保持所有方法名的一致性。

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

看看你的编译器为你提供什么方法​​。 这是我的基本差异。