Java의 CharSequence VS String?


421

Android에서 프로그래밍하면 대부분의 텍스트 값이로 예상됩니다 CharSequence.

왜 그런 겁니까? 장점은 무엇이며, CharSequenceover 를 사용할 때의 주된 영향은 String무엇입니까?

주요 차이점은 무엇이며 어떤 문제를 사용하고 서로 변환하면서 어떤 문제가 예상됩니까?


답변:


343

문자열은 CharSequences 이므로 문자열을 사용할 수 있으며 걱정할 필요가 없습니다. Android는 StringBuffers와 같은 다른 CharSequence 객체도 지정할 수 있도록함으로써 도움을 주려고합니다.


94
안드로이드가 콜백으로 CharSequence를 전달하고 charSeq.toString ()을 호출하는 경우를 제외하고.
Martin Konicek

100
그러나 CharSequencejavadoc 에서이 경고를 명심하십시오 .이 인터페이스는 equalshashCode메소드 의 일반적인 계약을 세분화하지 않습니다 . CharSequence따라서 구현하는 두 객체를 비교 한 결과는 일반적으로 undefined 입니다. 각 객체는 다른 클래스로 구현 될 수 있으며 각 클래스가 다른 인스턴스와 동일한 지 테스트합니다. 따라서 임의의 CharSequence인스턴스를 세트의 요소 또는 맵의 키로 사용하는 것은 적합하지 않습니다.
Trevor Robinson

3
@Pacerier : 실제적인 한계에 가깝다고 생각합니다. CharSequenceJDK 1.4에서는 문자 시퀀스를 포함하는 객체에 대한 제한적인 공통 인터페이스를 도입하기 위해 개조되었습니다. 이러한 개체 중 일부에는 다른 상태가 포함되어 있으므로 Object.equals"같은 문자 시퀀스를 포함합니다" 로 정의하는 것이 적합하지 않을 수 있습니다. NIO는 CharBuffer, 예를 들어, 단지 그 사이에 문자를 노출 position하고 limit는 AS CharSequence잠재적으로 많은 다른 문자를 잡고에도 불구하고.
Trevor Robinson

6
@TrevorRobinson, 디자인 버그는 데 그래서 equals/ hashCodeObject첫 번째 장소에서 ...
Pacerier

4
@Pacerier : IMHO Object또는에 디자인 버그가 없으며 CharSequence구현간에 동등성을 제공하기 위해 인터페이스가 필요하지 않습니다. 인터페이스 Collection사이에 평등을 제공하기 위해 두 개가 필요 Collection하지는 않지만 원하는 경우 인터페이스를 사용할 수 있습니다. IMHO CharSequence는 입력으로 제한되어야하며 리턴 유형에 대해서는 적게 사용해야합니다.
Brett Ryan

58

CharSequence= 인터페이스
String= 구체적인 구현

당신은 말했다 :

하나에서 다른 것으로 변환

에서 변환하는 것이 없습니다 String.

  • 모든 String대상 입니다 CharSequence.
  • 모든 CharSequence생산할 수 있습니다 String. 전화하십시오 CharSequence::toString. CharSequence발생하는 경우String 메서드는 자체 객체에 대한 참조를 반환합니다.

다시 말해 모든 String것이 a CharSequence이지만 모든 CharSequence것이 a는 아닙니다 String.

인터페이스 프로그래밍

안드로이드 프로그래밍, 대부분의 텍스트 값은 CharSequence에서 예상됩니다.

왜 그런 겁니까? CharSequence over String을 사용하면 어떤 이점이 있습니까?

일반적으로 인터페이스 프로그래밍은 구체적인 클래스 프로그래밍보다 낫습니다. 이는 유연성을 제공하므로 다른 코드를 손상시키지 않고 특정 인터페이스의 구체적인 구현간에 전환 할 수 있습니다.

API를 개발할 때다양한 상황에서 다양한 프로그래머가 사용할 를 가능한 가장 일반적인 인터페이스를 제공하고 사용하도록 코드를 작성하십시오. 이것은 호출 프로그래머에게 해당 인터페이스의 다양한 구현을 자유롭게 사용할 수 있도록합니다. 구현은 특정 상황에 가장 적합합니다.

예를 들어, Java Collections Framework를보십시오 . 당신의 API가 제공 또는 객체의 정렬 된 컬렉션을 소요하는 경우, 사용과 같이 메소드를 선언 List하기보다는 ArrayList, LinkedList또는 다른 어떤 제 3 자 구현 List.

여러 장소에서 사용되는 API를 작성하는 것과 달리 특정 장소에서 코드 만 사용하는 빠르고 더러운 작은 방법을 작성할 때 특정 콘크리트가 아닌 일반적인 인터페이스를 사용하는 데 신경 쓰지 않아도됩니다. 수업. 그러나 그럼에도 불구하고 가능한 가장 일반적인 인터페이스를 사용하는 것은 상처를줍니다.

주요 차이점은 무엇이며 예상되는 문제는 무엇입니까?

  • String당신은 전적으로 메모리에 하나의 텍스트가 있고 불변 이라는 것을 알고 있습니다.
  • 를 사용 CharSequence하면 구체적인 구현의 특정 기능이 무엇인지 알 수 없습니다.

CharSequence객체는 텍스트의 거대한 덩어리를 나타내고, 따라서 메모리 의미를 가지고 있습니다. 또는를 호출 할 때 함께 스티칭해야 toString하므로 성능 문제가 있는 별도의 추적 된 텍스트 덩어리가있을 수 있습니다. 구현시 원격 서비스에서 텍스트를 검색 할 수도 있으므로 대기 시간에 영향을 미칩니다.

서로 변환합니까?

일반적으로 앞뒤로 변환하지 않습니다. A String 입니다 CharSequence. 메소드가을 사용한다고 선언 CharSequence하면 호출 프로그래머가 String객체를 전달 StringBuffer하거나 a 또는와 같은 다른 것을 전달할 수 있습니다 StringBuilder. 메소드의 코드는 전달 된 모든 것을 사용하여 CharSequence메소드를 호출합니다 .

변환에 가장 가까운 것은 코드에 a가 수신되고 a CharSequence가 필요한 경우 String입니다. 아마도 당신은 인터페이스에 쓰여지지 String않고 클래스에 쓰여진 오래된 코드와 인터페이스하고있을 것입니다 CharSequence. 또는 반복적으로 반복하거나 분석하는 것과 같이 코드에서 텍스트를 집중적으로 사용할 수 있습니다. 이 경우 가능한 성능 저하를 한 번만 수행하려고합니다.toString . 그런 다음 완전히 기억에 담긴 단일 텍스트로 알고있는 것을 사용하여 작업을 진행하십시오.

뒤틀린 역사

허용 된 답변 에 대한 의견을 적어 둡니다 . CharSequence인터페이스는 기존의 클래스 구조로 개조, 그래서 몇 가지 중요한 미묘이 (가 equals()& hashCode()). 클래스 / 인터페이스에 태그가 지정된 다양한 버전의 Java (1, 2, 4 및 5)에 주목하십시오. 이상적으로 CharSequence처음부터 자리 잡았을 것입니다.

아래의 클래스 다이어그램은 Java 7/8에서 문자열 유형의 큰 그림을 보는 데 도움이 될 수 있습니다. 이 모든 것이 Android에 있는지 확실하지 않지만 전반적인 컨텍스트가 여전히 유용 할 수 있습니다.

다양한 문자열 관련 클래스 및 인터페이스 다이어그램


2
이 다이어그램을 직접 만드셨습니까? 다른 데이터 구조에 대한 이러한 다이어그램의 카탈로그가 있는지 궁금합니다.
user171943

4
@ user171943 저에 의해 작성된 OmniGroup의 OmniGraffle 앱을 사용하여 직접 제작했습니다 .
Basil Bourque

37

CharSequence를 사용하는 것이 가장 좋습니다. 그 이유는 String이 CharSequence를 구현하기 때문에 CharSequence에 String을 전달할 수 있지만 CharSequence는 String을 구현하지 않기 때문에 CharSequence를 String에 전달할 수 없다는 것입니다. 또한 Android에서이 EditText.getText()메소드는 Editable을 리턴합니다. 이 메소드는 CharSequence도 구현하며 쉽게 문자열로 전달되지 않고 하나에 전달 될 수 있습니다. CharSequence는 모든 것을 처리합니다!


7
당신은 할 수charSequence.toString()
호르헤 푸엔테스 곤잘레스에게

1
@jorge : 시퀀스가 ​​변경 가능한 경우 (또는 어떤 이유로 든 불변 문자열을 만들기 위해 문자 사본이 필요한 경우) 상대적으로 비효율적입니다.
Lawrence Dol

아주 좋은 설명 ..!
majurageer49

23

일반적으로 인터페이스를 사용하면 최소한의 부수적 피해로 구현을 변경할 수 있습니다. java.lang.String은 매우 인기가 있지만 특정 상황에서 다른 구현을 사용하고 싶을 수도 있습니다. 문자열이 아닌 CharSequences를 중심으로 API를 빌드하면 코드에서이를 수행 할 수 있습니다.


8

이것은 거의 확실하게 성능상의 이유입니다. 예를 들어 문자열이 포함 된 500k ByteBuffer를 통과하는 파서를 상상해보십시오.

문자열 내용을 반환하는 방법에는 3 가지가 있습니다.

  1. 구문 분석시 한 번에 한 문자 씩 String []을 작성하십시오. 시간이 많이 걸립니다. 캐시 된 참조를 비교하기 위해 .equals 대신 ==를 사용할 수 있습니다.

  2. 구문 분석시 오프셋을 사용하여 int []를 빌드 한 다음 get ()이 발생할 때 동적으로 문자열을 빌드하십시오. 각 문자열은 새 객체이므로 반환 값을 캐싱하지 않고 ==

  3. 구문 분석시 CharSequence []를 빌드하십시오. 바이트 버퍼로의 오프셋 이외의 새로운 데이터가 저장되지 않기 때문에 구문 분석은 # 1보다 훨씬 낮습니다. 얻을 때 String을 만들 필요가 없으므로 기존 객체에 대한 참조 만 반환하므로 성능은 # 1과 동일합니다 (# 2보다 훨씬 낫습니다).

CharSequence를 사용하면 얻을 수있는 처리 이점 외에도 데이터를 복제하지 않음으로써 메모리 공간을 줄일 수 있습니다. 예를 들어, 3 개의 텍스트 단락이 포함 된 버퍼가 있고 3 개 또는 단일 단락을 모두 반환하려는 경우이를 나타내려면 4 개의 문자열이 필요합니다. CharSequence를 사용하면 데이터가 포함 된 1 개의 버퍼와 시작 및 길이를 추적하는 CharSequence 구현의 4 개 인스턴스 만 필요합니다.


6
plz를 참조하십시오. 무슨 일이 일어나고 있는지 무작위로 추측하는 것처럼 들립니다. 또한 나는 당신의 주장이 유효하지 않다. 단순히 500k 바이트 버퍼를 문자열로 저장하고 하위 문자열을 반환 할 수 있습니다.이 문자열은 더 빠르고 더 일반적입니다.
kritzikratzi

6
@kritzikratzi-JDK7부터 String의 하위 문자열은 더 이상 기본 배열을 공유하지 않으며 "미치게 빠르지"않습니다. 부분 문자열의 길이에 O (N) 시간이 걸리고 호출 할 때마다 기본 문자의 사본을 생성하므로 많은 가비지가 발생합니다.
BeeOnRope

@kritzikratzi 변경의 이유는 복사본을 만들지 않으면 원본 문자열이 모든 하위 문자열의 수명 동안 유지되기 때문입니다. 부분 문자열은 일반적으로 원본의 작은 부분 일 뿐이며 사용 방법에 따라 무기한 지속될 수 있으므로 하위 문자열을 원래 문자열보다 훨씬 오래 사용하면 가비지가 더 많이 발생합니다. 흥미로운 대안은 하위 문자열 대 부모 문자열 크기의 비율을 기반으로 복사할지 여부를 결정하는 것이지만 자체 CharSequence구현 을 롤링해야 합니다.
JAB

1
아마도 요점을 놓쳤지만이 대답은 말도 안됩니다. A CharSequence인터페이스입니다. 정의에 따르면 자체 구현이 없으므로 논의한 구현 세부 정보 가 없습니다 . A String는 인터페이스 를 구현하는 몇 가지 구체적인 클래스 중 하나입니다 CharSequence. 그래서이 String 있다CharSequence . 당신의 성능 세부 사항을 비교할 수 StringStringBufferStringBuilder,하지만 CharSequence. "CharSequence를 사용하여 얻는 처리 이익"을 작성하는 것은 의미가 없습니다.
Basil Bourque

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는 다양한 유형의 텍스트 문자열을위한 우산입니다. 다음은 일반적인 것들입니다.

( 여기 에서 차이점에 대한 자세한 내용은 여기를 참조하십시오 .)

CharSequence객체 가 있으면 실제로 구현하는 클래스 중 하나의 객체입니다 CharSequence. 예를 들면 다음과 같습니다.

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

일반적인 우산 유형과 같은 장점은 CharSequence단일 방법으로 여러 유형을 처리 할 수 ​​있다는 것입니다. 예를 들어 CharSequence매개 변수로 a를 사용 하는 메서드가 있으면 a String또는 a를 전달할 수 있으며 SpannableStringBuilder둘 중 하나를 처리합니다.

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

a String는 단지 한 종류 일 뿐이라고 말할 수 CharSequence있습니다. 그러나와 달리 CharSequence실제 클래스이므로 객체를 만들 수 있습니다. 그래서 당신은 이것을 할 수 있습니다 :

String myString = new String();

그러나 당신은 이것을 할 수 없습니다 :

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

준수하는 CharSequence규칙 목록 일 뿐이 므로 String다음을 수행 할 수 있습니다.

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를 인스턴스화 String할 수 는 있지만 CharSequence인터페이스이기 때문에 수행 할 수 없습니다 . CharSequence공식 Java 웹 사이트에서 다른 구현을 찾을 수 있습니다 .


-4

CharSequence는 문자열을 구현하는 읽을 수있는 char 값 시퀀스입니다. 그것은 4 가지 방법이 있습니다

  1. charAt (int 인덱스)
  2. 길이()
  3. subSequence (int start, int end)
  4. toString ()

CharSequence 설명서를 참조하십시오


6
CharSequence구현하지 않습니다 String. 그러나 대화는 사실입니다.
seh

1
이 넌센스 답변을 제거하십시오
J. Doe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.