在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字节码。 在那里你会注意到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
使用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
许多地方使用它,就像我们使用Collection
或List
接口代替ArrayList
或LinkedList
实现一样。
界面与类
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变化。
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
对象。 作为一个实现CharSequence
的String
,它也是一个CharSequence
。 (你可以阅读这个关于编码接口的post )。
下一行:
String str = "hello";
稍微复杂一点。 Java中的String
文字被保存在一个池中,因此这一行上的"hello"
与第一行中的"hello"
是同一个对象(标识符)。 因此,这一行只将相同的String
文字分配给str
。
在这一点上, obj
和str
都是对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。
看看你的编译器为你提供什么方法。 这是我的基本差异。