CharSequence VS Javaの文字列?


421

Androidでのプログラミングでは、ほとんどのテキスト値がで期待されていCharSequenceます。

何故ですか?メリットは何ですか?を使用CharSequenceすることの主な影響は何Stringですか?

主な違いは何ですか?それらを使用し、別のものに変換する際に予想される問題は何ですか?


回答:


343

文字列はCharSequencesであるため、文字列を使用するだけでかまいません。Androidは、StringBuffersなどの他のCharSequenceオブジェクトも指定できるようにすることで、単に役立つようにしています。


94
AndroidがコールバックでCharSequenceを渡し、文字列が必要な場合を除いて、charSeq.toString()を呼び出します。
Martin Konicek、2011

100
ただし、このCharSequencejavadocの警告に注意してください。このインターフェースは、equalsおよびhashCodeメソッドの一般的な規約を洗練していません。CharSequenceしたがって、実装する2つのオブジェクトを比較した結果は、一般にundefinedです。各オブジェクトは異なるクラスによって実装される可能性があり、各クラスがそのインスタンスを他のインスタンスと等しいかどうかテストできるとは限りません。したがって、任意のCharSequenceインスタンスをセットの要素として、またはマップのキーとして使用することは不適切です。
Trevor Robinson

3
@Pacerier:実際の制限のほうが多いと思います。CharSequenceJDK 1.4の改良版であり、文字シーケンスを含むオブジェクトへの限定目的の共通インターフェースを導入しました。これらのオブジェクトの一部には他の状態が含まれているためObject.equals、「同じ文字シーケンスを含む」と定義しても意味がない場合があります。CharBufferたとえばNIOは、他の多くの文字を保持している可能性があるにもかかわらず、positionとの間の文字のみを公開します。limitCharSequence
Trevor Robinson、

6
@TrevorRobinson、それで、設計バグはそもそもequals/ hashCodeオンObjectになっています...
Pacerier '19

4
@Pacerier:IMHO Objectまたはのどちらにも設計上のバグはありませんCharSequence。実装間の等価性を提供するためにインターフェイスは必要ありません。インターフェイスCollection間の同等性を提供するために2つのは必要ありませんが、必要に応じて2つを使用Collectionできます。IMHO CharSequenceは入力に限定され、戻り値の型にはあまり使用されません。
Brett Ryan

58

CharSequence=インターフェース
String=具体的な実装

あなたが言った:

あるものから別のものへの変換

からの変換はありませんString

  • すべてのStringオブジェクトがありますCharSequence
  • すべてCharSequenceがを生成できStringます。を呼び出しCharSequence::toStringます。CharSequenceがたまたまの場合、Stringメソッドは自身のオブジェクトへの参照を返します。

言い換えれば、すべてのはStringあるCharSequenceが、すべてではないCharSequenceですString

インターフェイスへのプログラミング

Androidでのプログラミングでは、ほとんどのテキスト値はCharSequenceで期待されます。

何故ですか?文字列よりもCharSequenceを使用する主な影響は何ですか?

一般に、インターフェースへのプログラミングは、具象クラスへのプログラミングよりも優れています。これにより柔軟性が生まれるため、他のコードを壊すことなく、特定のインターフェースの具体的な実装を切り替えることができます。

さまざまな状況でさまざまなプログラマーが使用するAPIを開発するときは、可能な限り最も一般的なインターフェースを提供および取得するようにコードを記述します。これにより、呼び出し側のプログラマは、特定のコンテキストに最適な実装である、そのインターフェースのさまざまな実装を自由に使用できます。

たとえば、Java Collections Frameworkを見てください。あなたのAPIを提供したり、オブジェクトの順序付きコレクションを取る場合は、使用して、あなたのメソッドを宣言するListのではなくArrayListLinkedListまたは任意の他のサードパーティの実装List

複数の場所で使用されるAPIを作成するのではなく、1つの特定の場所でコードによってのみ使用される簡単なメソッドを作成する場合、特定の具象ではなく、より一般的なインターフェイスを使用する必要はありません。クラス。しかし、それでも、できる限り一般的なインターフェースを使用することは害になります。

主な違いは何ですか、それらを使用しているときに予想される問題は、

  • Stringあなたが知っていると、あなたはあなたが完全にメモリにある単一のテキストを持ち、不変です。
  • を使用するCharSequenceと、具体的な実装の特定の機能が何であるかがわかりません。

CharSequenceオブジェクトは、テキストの巨大な塊を表し、したがって、メモリへの影響を持っているかもしれません。または、個別に追跡されるテキストのチャンクが多数ある場合があります。これらのテキストは、を呼び出すときにつなぎ合わせる必要があるtoStringため、パフォーマンスの問題があります。この実装では、リモートサービスからテキストを取得することもあるので、レイテンシに影響します。

と別のものに変換しますか?

通常、前後に変換することはありません。AがString ありますCharSequence。あなたの方法は、それが取ることを宣言した場合CharSequence、呼び出しプログラマが渡すことStringのオブジェクトを、またはのような何か他のもの渡すことStringBufferかをStringBuilder。メソッドのコードは、渡されたものを何でも使用して、CharSequenceメソッドのいずれかを呼び出します。

変換に最も近いのは、コードがを受け取り、CharSequenceが必要であることがわかっている場合ですString。おそらく、インターフェースに書き込まれるのStringではなく、クラスに書き込まれた古いコードとインターフェースしている可能性がありCharSequenceます。または、コードがテキストで集中的に機能する場合があります。たとえば、繰り返しループしたり、分析したりします。その場合、パフォーマンスヒットを1回だけ受けたいので、最初に呼び出しますtoString。次に、完全にメモリ内にある1つのテキストであることがわかっているものを使用して作業を続行します。

ねじれた歴史

承認された回答に加えられたコメントに注意してください。CharSequenceインターフェイスは、既存のクラス構造に改造されたので、いくつかの重要な微妙な点は、(あるequals()hashCode())。クラス/インターフェースにタグ付けされたJavaのさまざまなバージョン(1、2、4、および5)に注意してください。何年にもわたってかなりのチャーンが発生しています。理想的にCharSequenceは最初から存在していたはずですが、それは人生です。

以下のクラス図は、Java 7/8の文字列型の全体像を理解するのに役立ちます。これらすべてがAndroidに存在するかどうかはわかりませんが、全体的なコンテキストが役立つ場合があります。

さまざまな文字列関連のクラスとインターフェースの図


2
この図を自分で作成しましたか?さまざまなデータ構造に対してこれらの図のカタログがあるかどうか疑問に思います。
user171943

4
@ user171943私が作成、OmniGroupのOmniGraffleアプリを使用して手作り。
バジルブルク2018年

37

CharSequenceを使用するのが最善だと思います。その理由は、文字列はCharSequenceを実装するため、文字列をCharSequenceに渡すことができます。ただし、CharSequenceは文字列を実装しないため、文字列にCharSequenceを渡すことはできません。また、Androidでは、このEditText.getText()メソッドはEditableを返します。これは、CharSequenceも実装しているため、文字列に簡単に渡すことはできませんが、1つに簡単に渡すことができます。CharSequenceがすべてを処理します!


7
あなたができることcharSequence.toString()
ホルヘ・フエンテス・ゴンサレス

1
@jorge:シーケンスが変更可能な場合(または何らかの理由で不変の文字列を作成するために文字のコピーが必要な場合)は、比較的非効率的です。
Lawrence Dol、2015年

とてもいい説明..!
majurageerthan

23

一般に、インターフェースを使用すると、付随的な損傷を最小限に抑えて実装を変更できます。java.lang.Stringは非常に人気がありますが、特定のコンテキストでは別の実装を使用したい場合があります。文字列ではなくCharSequencesを中心にAPIを構築することにより、コードはそのための機会を提供します。


8

これはほぼ間違いなくパフォーマンス上の理由です。たとえば、文字列を含む500kのByteBufferを通過するパーサーを想像してみてください。

文字列コンテンツを返すには、3つの方法があります。

  1. 一度に1文字ずつ、解析時にString []を作成します。これにはかなりの時間がかかります。.equalsの代わりに==を使用して、キャッシュされた参照を比較できます。

  2. 解析時にオフセットを使用してint []を作成し、get()が発生したときに動的にStringを作成します。各文字列は新しいオブジェクトになるため、戻り値のキャッシュや==の使用はありません

  3. 解析時にCharSequence []を作成します。(バイトバッファーへのオフセット以外の)新しいデータは保存されないため、解析は#1よりはるかに低くなります。取得時には、文字列を構築する必要がないため、既存のオブジェクトへの参照のみを返すため、取得パフォーマンスは#1(#2よりはるかに優れています)と同等です。

CharSequenceを使用することで得られる処理の向上に加えて、データを複製しないことでメモリフットプリントも削減します。たとえば、テキストの3つの段落を含むバッファーがあり、3つすべてまたは1つの段落を返す場合、これを表すには4つの文字列が必要です。CharSequenceを使用すると、データを含む1つのバッファーと、開始と長さを追跡するCharSequence実装の4つのインスタンスのみが必要になります。


6
plzを参照します。何が起こっているのかをランダムに推測しているように聞こえます。また、私はあなたの議論が有効であるとは思いません。そもそも500kバイトバッファを文字列として格納し、部分文字列を返すだけの場合があります。これは非常に高速で、はるかに一般的です。
kritzikratzi

6
@kritzikratzi-JDK7以降、文字列の部分文字列は基になる配列を共有せず、「非常に高速」ではありません。部分文字列の長さでO(N)時間を要し、呼び出すたびに基礎となる文字のコピーを生成します(大量のゴミ)。
BeeOnRope 2013

@kritzikratzi変更の理由は、コピーが作成されなかった場合、元の文字列がすべての部分文字列の存続期間中保持されるためだと思います。通常、部分文字列は元の文字列のほんの一部であり、その使用方法によっては無期限に続く可能性があるため、部分文字列が元の文字列よりもはるかに長い間使用されていると、ガベージがさらに増えることがよくあります。興味深い代替手段は、サブストリングと親ストリングのサイズの比率に基づいてコピーするかどうかを決定することですがCharSequence、そのために独自の実装をロールする必要があります。
JAB 2014

1
ポイントを逃したのかもしれませんが、この答えはナンセンスです。A CharSequenceインターフェースです。定義上、独自の実装がないため説明する実装の詳細はありません。A Stringは、インターフェースを実装するいくつかの具象クラスの1つですCharSequence。そうString ですCharSequence。あなたはのパフォーマンスの詳細を比較することができStringStringBufferStringBuilderではなくCharSequence。「CharSequenceを使用して得られる処理利益」を書いても意味がありません。
バジルブルク2017

7

実際のAndroidコードで発生する問題は、それらをCharSequence.equalsと比較することは有効ですが、必ずしも意図したとおりに機能しないことです。

EditText t = (EditText )getView(R.id.myEditText); // Contains "OK"
Boolean isFalse = t.getText().equals("OK"); // will always return false.

比較は

("OK").contentEquals(t.GetText()); 

5

CharSequence

A CharSequenceはインターフェースであり、実際のクラスではありません。インターフェースは、インターフェースを実装する場合にクラスに含める必要がある一連のルール(メソッド)です。Androidでは、a CharSequenceはさまざまなタイプのテキスト文字列の傘です。一般的なものは次のとおりです。

  • String (スタイリングスパンのない不変のテキスト)
  • StringBuilder (スタイリングスパンのない可変テキスト)
  • SpannableString (スタイルスパンを含む不変のテキスト)
  • SpannableStringBuilder (スタイリングスパンの可変テキスト)

(これらの違いの詳細については、こちらをご覧ください。)

CharSequenceオブジェクトがある場合、それは実際にはを実装するクラスの1つのオブジェクトですCharSequence。例えば:

CharSequence myString = "hello";
CharSequence mySpannableStringBuilder = new SpannableStringBuilder();

のような一般的なアンブレラ型を持つことの利点はCharSequence、単一のメソッドで複数の型を処理できることです。たとえば、CharSequenceaをパラメーターとして受け取るメソッドがある場合、a Stringまたはa SpannableStringBuilderを渡すことができ、どちらかを処理します。

public int getLength(CharSequence text) {
    return text.length();
}

ストリング

a Stringは1種類にすぎないと言えCharSequenceます。ただし、とは異なりCharSequence、これは実際のクラスなので、そこからオブジェクトを作成できます。だからあなたはこれを行うことができます:

String myString = new String();

しかし、あなたはこれを行うことができません:

CharSequence myCharSequence = new CharSequence(); // error: 'CharSequence is abstract; cannot be instantiated

CharSequenceString準拠するルールのリストにすぎないので、次のようにすることができます。

CharSequence myString = new String();

この方法は、を要求任意の時間があることを意味しCharSequence、それ与えるために罰金ですString

String myString = "hello";
getLength(myString); // OK

// ...

public int getLength(CharSequence text) {
    return text.length();
}

ただし、その逆は当てはまりません。メソッドがStringパラメータをとる場合、CharSequenceそれが実際にSpannableStringはや他の種類のである可能性があるため、であることが一般的に知られているものを渡すことはできませんCharSequence

CharSequence myString = "hello";
getLength(myString); // error

// ...

public int getLength(String text) {
    return text.length();
}

0

CharSequenceインターフェースであり、Stringそれを実装します。aをインスタンス化できますStringCharSequence、それはインターフェースであるため、それを実行できませんでした。その他の実装についてCharSequenceは、Javaの公式Webサイトを参照してください。


-4

CharSequenceは、Stringを実装する読み取り可能なchar値のシーケンスです。4つの方法があります

  1. charAt(intインデックス)
  2. length()
  3. subSequence(int開始、int終了)
  4. toString()

CharSequenceのドキュメントを参照してください


6
CharSequence実装していませんString。ただし、その逆は当てはまります。
seh 2016

1
このナンセンスな答えを削除してください
J. Doe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.