web-dev-qa-db-ja.com

javaのCharSequenceとStringの正確な違い

私はこれを読みます 前の投稿CharSequenceString を実装し、CharSequenceが文字のシーケンスであるという事実を除いて、StringとStringの正確な違いは何ですか?例えば:

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

「hello」がobjに割り当てられ、再びstrに割り当てられるとどうなりますか?

98
Amith

一般的な違い

CharSequence のほかに String インターフェースを実装するいくつかのクラスがあります。これらの中には

  • StringBuilder 変更可能な可変長文字シーケンスの場合
  • CharBuffer 変更可能な固定長の低レベル文字シーケンス用

CharSequenceを受け入れるメソッドは、これらすべてに対して同様にうまく機能します。 Stringのみを受け入れるメソッドは、変換が必要です。したがって、内部を気にしないすべての場所でCharSequenceを引数型として使用することは賢明です。ただし、実際にStringを返す場合は、Stringを戻り値の型として使用する必要があります。呼び出し側のメソッドが実際にStringを必要とする場合、戻り値の可能な変換を避けるためです。

また、マップキーは変更してはならないため、マップではStringではなくCharSequenceをキータイプとして使用する必要があることに注意してください。つまり、Stringの不変の性質が不可欠な場合があります。

特定のコードスニペット

貼り付けたコードについては、単にコンパイルし、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_33StringBuilder.append(Object)の代わりにStringBuilder.append(CharSequence)を使用して+ objをコンパイルすることに少し驚いていることを告白しなければなりません。前者はおそらくオブジェクトのtoString()メソッドへの呼び出しを伴うのに対して、後者はより効率的な方法で可能になるはずです。一方、String.toString()は、単にString自体を返すため、ペナルティはほとんどありません。したがって、StringBuilder.append(String)は1つのメソッド呼び出しでより効率的になる可能性があります。

97
MvG

tl; dr

1つはインターフェイス( CharSequence )で、もう1つはそのインターフェイスの具体的な実装( String )です。

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

インターフェイスとしては、通常CharSequenceStringよりも一般的に見られますが、いくつかのねじれた歴史により、インターフェイスが何年も定義されていましたafter実装。そのため、古いAPIではStringがよく見られますが、新しいAPIではCharSequenceが引数と戻り値の型の定義に使用される傾向があります。

詳細

最近では、一般的にAPI /フレームワークは主にインターフェースのエクスポートに、具体的なクラスの二次的なエクスポートに焦点を合わせる必要があることを知っています。しかし、私たちはこのレッスンをいつもそれほどよく知っていませんでした。

StringクラスはJavaで最初に登場しました。後になってから、彼らはCharSequenceという正面向きのインターフェースを配置しました。

ねじれた歴史

少しの歴史が理解に役立つかもしれません。

初期の頃、Javaは、業界をアニメーション化するインターネット/ Webマニアのために、少し前に市場に駆けつけました。一部のライブラリは、本来考えられていたほど熟考されていませんでした。文字列処理はそれらの領域の1つでした。

また、Javaは、最も初期の生産指向の非アカデミック オブジェクト指向プログラミング(OOP) 環境の1つでした。 OOPの唯一の成功した実世界のラバーミーツザロード実装は、 Smalltalk のいくつかの限定バージョンであり、その後 Objective-C with NeXTSTEP / OpenStep したがって、多くの実践的な教訓はまだ学ばれていませんでした。

Javaは String クラスと StringBuffer クラスで始まりました。しかし、これら2つのクラスは無関係であり、継承やインターフェースによって互いに結び付けられていません。後で、Javaチームは、文字列関連の実装を相互交換可能にするために、文字列関連の実装を統一するタイがあるべきだと認識しました。 Java 4では、チームは CharSequence インターフェースを追加し、そのインターフェースをStringおよびString Bufferに遡及的に実装し、別の実装を追加しました CharBuffer 。後でJava 5に StringBuilder が追加されました。これは基本的に非同期であるため、StringBufferの多少速いバージョンです。

そのため、これらの文字列指向のクラスは少し複雑であり、学ぶのは少し混乱します。 Stringオブジェクトを取得して返すために、多くのライブラリとインターフェイスが構築されました。現在、このようなライブラリは一般的にCharSequenceを期待するように構築されるべきです。ただし、(a)Stringは依然としてマインドスペースを支配しているようです。(b)さまざまなCharSequence実装を混在させると、微妙な技術的な問題が発生する可能性があります。後知恵の20/20ビジョンを見ると、このすべての文字列をより適切に処理できたはずであることがわかりますが、ここにあります。

理想的には、Javaは、 String を使用するのと同じように、現在Collectionを使用している多くの場所で使用されるインターフェースおよび/またはスーパークラスで開始されます。 List インターフェースの代わりに ArrayList または LinkedList 実装。

インターフェイスとクラス

CharSequenceの主な違いは、 実装 ではなく、 interface であることです。つまり、CharSequenceを直接インスタンス化することはできません。むしろ、そのインターフェースを実装するクラスの1つをインスタンス化します。

たとえば、ここにはxのように見えるCharSequenceがありますが、その下は実際にはStringBuilderオブジェクトです。

CharSequence x = new StringBuilder( "dog" );

これは、文字列リテラルを使用する場合、それほど明白ではありません。文字を引用符で囲んだソースコードを表示する場合、コンパイラはそれを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

テキストブロック

ますます多くの emoji および Unicode サポートの連続したバージョンに付属している他の文字を除き、近年ではあまり変更されていませんJavaでテキストを操作するために…Java 13.まで.

Java 13は、新機能のプレビューを提供する場合があります:テキストブロック。これにより、SQLなどの埋め込みコード文字列の記述がより便利になります。 JEP 355 を参照してください。

この作業の前に JEP 326:Raw String Literals(Preview) がありました。

85
Basil Bourque

CharSequenceはコントラクト( interface )であり、Stringはこのコントラクトの 実装 です。

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

documentation for CharSequenceは次のとおりです。

CharSequenceは、読み取り可能なchar値のシーケンスです。このインターフェイスは、さまざまな種類のcharシーケンスへの統一された読み取り専用アクセスを提供します。 char値は、基本多言語面(BMP)またはサロゲートの文字を表します。詳細については、Unicode文字表現を参照してください。

21

stringがCharSequenceを実装し、Stringが文字のシーケンスであるという事実以外。

コードではいくつかのことが起こります。

CharSequence obj = "hello";

これにより、StringオブジェクトであるStringリテラル"hello"が作成されます。 Stringを実装するCharSequenceであると同時に、CharSequenceでもあります。 ( インターフェイスへのコーディングに関するこの投稿 を読むことができます)。

次の行:

String str = "hello";

もう少し複雑です。 JavaのStringリテラルはプールに保持される(インターン)ため、この行の"hello"は最初の行の"hello"と同じオブジェクト(ID)です。 。したがって、この行は、Stringに同じstrリテラルのみを割り当てます。

この時点で、objstrは両方ともStringリテラル"hello"への参照であるため、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));
}
12
assylias

私はそれが一種の明白であることを知っていますが、CharSequenceはインターフェイスですが、Stringは具体的なクラスです:)

Java.lang.Stringは、このインターフェイスの実装です...

2
Mark Bramnik

UTF-8を検討してください。 UTF-8では、Unicodeコードポイントは1バイト以上から構築されます。 UTF-8バイト配列をカプセル化するクラスは、CharSequenceインターフェイスを実装できますが、ほとんどの場合、文字列ではありません。確かに、Stringが期待されるUTF-8バイト配列を渡すことはできませんが、CharSequenceを許可するためにコントラクトが緩和されると、CharSequenceを実装するUTF-8ラッパークラスを確実に渡すことができます。私のプロジェクトでは、XMLのデータ圧縮を提供するCBTF8Field(圧縮バイナリ転送形式-8ビット)というクラスを開発しており、CharSequenceインターフェイスを使用してCBTF8バイト配列から文字配列(UTF-16)への変換を実装しようとしています)およびバイト配列(UTF-8)。

ここに来たのは、サブシーケンス契約を完全に理解するためです。

2

CharSequence のJava AP​​Iから:

CharSequenceは、読み取り可能な文字のシーケンスです。このインターフェイスは、さまざまな種類の文字シーケンスへの統一された読み取り専用アクセスを提供します。

このインターフェイスは、すべてのメソッド名の一貫性を保つために StringCharBuffer 、および StringBuffer によって使用されます。

1

CharSequenceには、Stringで使用できる非常に便利なメソッドはありません。ドキュメントを参照したくない場合は、objと入力します。およびstr。

そして、あなたのコンピレーターがあなたに提供する方法を見てください。それが私にとっての基本的な違いです。

0
Doszi89