Java CharSequence VS String?


Yanıtlar:


343

Dizeler CharSequences'dır , bu yüzden endişelenmeyin, sadece Dizeleri kullanabilirsiniz. Android, StringBuffers gibi diğer CharSequence nesnelerini de belirtmenize izin vererek yardımcı olmaya çalışıyor.


94
Dışında Android bana bir geri çağrısında bir CharSequence geçer ve ben bir String - call charSeq.toString () gerekir.
Martin Konicek

100
Ancak bu uyarıyı CharSequencejavadoc'tan aklınızda bulundurun : Bu arayüz equalsve hashCodeyöntemlerinin genel sözleşmelerini rafine etmez . CharSequenceDolayısıyla, uygulanan iki nesnenin karşılaştırılmasının sonucu, genel olarak tanımsızdır . Her nesne farklı bir sınıf tarafından uygulanabilir ve her sınıfın kendi örneklerini diğeriyle eşitlik açısından test edebileceğine dair bir garanti yoktur. Bu nedenle, rastgele CharSequenceörneklerin bir kümedeki öğeler veya bir haritadaki anahtarlar olarak kullanılması uygun değildir.
Trevor Robinson

3
@ Pacer: Bence bu daha pratik bir sınırlama. CharSequenceJDK 1.4'te karakter dizileri içeren nesnelere sınırlı amaçlı ortak bir arabirim sunmak için yapılan bir uyarlamadır. Bu nesnelerin bazıları başka bir durum içerir, bu nedenle Object.equals"aynı karakter dizisini içerir" olarak tanımlamak anlamlı olmayabilir . MİT CharBuffer, örneğin, sadece onun arasındaki karakterleri ortaya çıkarır positionve limitsıra CharSequencepotansiyel diğer birçok karakterleri tutarak rağmen.
Trevor Robinson

6
@TrevorRobinson, tasarım hata yaşıyor Yani equals/ hashCodeüzerinde Objectilk etapta ....
Pacerier

4
@Pacerier: IMHO İkisinde de bir tasarım hatası yok Objectveya CharSequenceuygulamalar arasında eşitlik sağlaması için herhangi bir arayüz gerekli değil. Arayüz Collectionarasında eşitlik sağlamak için hiçbir ikiye gerek yoktur Collection, ancak istedikleri takdirde bunu yapabilirler. IMHO CharSequencegirişlerle sınırlı olmalı ve dönüş türleri için daha az kullanılmalıdır.
Brett Ryan

58

CharSequence= arayüz
String= somut uygulama

Dedin:

birinden diğerine dönüştürme

Kaynağından dönüştürme yok String.

  • Her Stringnesne olan birCharSequence .
  • Herkes CharSequenceüretebilir String. Arayın CharSequence::toString. Olursa CharSequencea String, yöntem kendi nesnesine bir başvuru döndürür.

Başka bir deyişle, her Stringbiri bir CharSequence, ama her CharSequencebiri birString .

Bir arayüze programlama

Android'de programlandığında, metin değerlerinin çoğunun CharSequence'da olması bekleniyor.

Neden? Faydası nedir ve CharSequence'ı String üzerinde kullanmanın ana etkileri nelerdir?

Genel olarak, bir arayüze programlama, somut sınıflara programlamadan daha iyidir. Bu esneklik sağlar, böylece başka bir kodu kırmadan belirli bir arayüzün somut uygulamaları arasında geçiş yapabiliriz.

Bir API geliştirirkenÇeşitli durumlarda çeşitli programcılar tarafından kullanılacak , mümkün olan en genel arayüzleri vermek ve almak için kodunuzu yazın. Bu, çağrı yapan programcıya, hangi bağlam için en iyi uygulama olursa olsun, bu arayüzün çeşitli uygulamalarını kullanma özgürlüğü verir.

Örneğin, Java Koleksiyonlar Çerçevesi'ne bakın . API verir veya nesnelerin sıralanmış koleksiyonunu sürerse, kullanırken de yöntemlerini bildirmek Listyerine ArrayList, LinkedListya başka 3. taraf uygulama List.

Birden fazla yerde kullanılacak bir API yazmak yerine, kodunuz tarafından yalnızca belirli bir yerde kullanılacak hızlı ve kirli küçük bir yöntem yazarken, belirli bir betondan ziyade daha genel arabirimi kullanmakla uğraşmanıza gerek yoktur. sınıf. Ancak o zaman bile, yapabileceğiniz en genel arayüzü kullanmak zarar verir.

Temel farklar nelerdir ve bunları kullanırken hangi sorunların beklendiği,

  • Bir ile Stringsize tamamen bellekte, tek bir metin parçası var biliyorum ve sabittir.
  • A ile CharSequence, somut uygulamanın belirli özelliklerinin ne olabileceğini bilmiyorsunuz.

CharSequenceNesne metnin muazzam bir yığın temsil eder ve bu nedenle bellek etkileri vardır olabilir. Veya aradığınızda birbirine dikilmesi gereken toStringve bu nedenle performans sorunları olan, ayrı ayrı izlenen birçok metin parçası olabilir . Uygulama, uzak bir hizmetten metin alıyor olabilir ve bu nedenle gecikme etkileri vardır.

ve birinden diğerine dönüşüm?

Genelde ileri geri dönüşüm yapmayacaksınız. Bir String olan bir CharSequence. Metodunuz bunun bir zaman aldığını bildirirse CharSequence, çağıran programcı bir Stringnesneyi veya bir StringBufferveya gibi başka bir şey iletebilir StringBuilder. Yönteminizin kodu, geçirilen her şeyi kullanır ve CharSequenceyöntemlerden herhangi birini çağırır .

Dönüştürmek için en yakın kodunuz bir alır CharSequenceve bir ihtiyacınız olduğunu biliyorum String. Belki de arayüze yazılmak Stringyerine sınıfa yazılan eski kodlarla CharSequencearayüz oluşturuyorsunuz. Ya da kodunuz tekrar tekrar döngü yapmak veya başka bir şekilde analiz etmek gibi metinle yoğun bir şekilde çalışacaktır. Bu durumda, olası herhangi bir performans isabetini sadece bir kez almak istersiniz, böylecetoString öne . Ardından, tamamen bellekte tek bir metin parçası olarak bildiğiniz şeyi kullanarak çalışmalarınıza devam edin.

Bükülmüş tarih

Kabul edilen cevapta yapılan yorumları not edin . CharSequenceArayüz mevcut sınıf yapıları üzerine sonradan, bu yüzden bazı önemli incelikler (vardır equals()& hashCode()). Sınıflar / arayüzler üzerinde etiketlenen çeşitli Java sürümlerine (1, 2, 4 ve 5) dikkat edin - yıllar içinde biraz çalkalama. İdeal CharSequenceolarak başlangıçtan itibaren yerinde olurdu, ama hayat böyle.

Aşağıdaki sınıf şemam, Java 7/8'de dize türlerinin büyük resmini görmenize yardımcı olabilir. Tüm bunların Android'de mevcut olup olmadığından emin değilim, ancak genel bağlam hala sizin için yararlı olabilir.

string ile ilgili çeşitli sınıfların ve arayüzlerin şeması


2
Bu diyagramı kendiniz yaptınız mı? farklı veri yapıları için bu diyagramların bir kataloğu olup olmadığını merak etmek.
user171943

4
@ user171943 Benim tarafımdan yazılmış , OmniGroup'tan OmniGraffle uygulaması kullanılarak el yapımı .
Basil Bourque

37

CharSequence'ı kullanmanın en iyisi olduğuna inanıyorum. Bunun nedeni String'in CharSequence'ı uygulamasıdır, bu nedenle bir String'i CharSequence'a geçirebilirsiniz, ancak CharSequence String'i uygulamadığı için CharSequence'ı bir String'e geçiremezsiniz. AYRICA, Android'de EditText.getText()yöntem, CharSequence'ı uygulayan ve kolayca bir String'e değil, kolayca bir taneye geçirilebilen bir Düzenlenebilir döndürür. CharSequence hepsini halleder!


7
YapabilirsinizcharSequence.toString()
Jorge Fuentes González

1
@jorge: Sekans değişebilirse (veya herhangi bir nedenle değişmez dizgede yapmak için karakterlerin bir kopyasını gerektirir) bunun nispeten verimsiz olması dışında.
Lawrence Dol

çok güzel bir açıklama ..!
majurageerthan

23

Genel olarak bir arabirim kullanmak, uygulamayı minimum teminat hasarı ile değiştirmenize izin verir. Her ne kadar java.lang.String süper popüler olsa da, belirli bağlamlarda başka bir uygulama kullanmak isteyebilirsiniz. API'yı Dizeler yerine CharSequences etrafında oluşturarak kod, bunu yapma fırsatı verir.


8

Bu neredeyse kesinlikle performans nedenleridir. Örneğin, 500k ByteBuffer dizeleri içeren bir ayrıştırıcı düşünün.

Dize içeriğini döndürmek için 3 yaklaşım vardır:

  1. Ayrıştırma zamanında birer birer karakter olmak üzere bir String [] oluşturun. Bu fark edilir bir zaman alacaktır. Önbelleğe alınan referansları karşılaştırmak için .equals yerine == kullanabiliriz.

  2. Ayrıştırma zamanında ofsetleri olan bir int [] oluşturun, ardından bir get () gerçekleştiğinde dinamik olarak String oluşturun. Her Dize yeni bir nesne olacaktır, bu nedenle döndürülen değerleri önbelleğe alma ve == kullanma

  3. Ayrıştırma zamanında bir CharSequence [] oluşturun. Hiçbir yeni veri depolanmadığından (bayt arabelleğine ofsetler dışında), ayrıştırma # 1'den çok daha düşüktür. Zamanında, bir Dize oluşturmamız gerekmez, bu nedenle get performansı # 1'e eşittir (# 2'den çok daha iyidir), çünkü sadece mevcut bir nesneye bir referans döndürüyoruz.

CharSequence'ı kullanarak elde ettiğiniz işlem kazançlarına ek olarak, verileri çoğaltmayarak bellek kapladığı alanı da azaltırsınız. Örneğin, 3 paragraflık metin içeren bir ara belleğe sahipseniz ve 3 veya tek bir paragrafın tümünü döndürmek istiyorsanız, bunu temsil etmek için 4 Dizeye ihtiyacınız vardır. CharSequence'ı kullanarak yalnızca verilerle bir arabellek ve başlangıç ​​ve uzunluğu izleyen bir CharSequence uygulamasının 4 örneğine ihtiyacınız vardır.


6
referanslar plz. neler olduğunu rastgele tahmin etmek gibi geliyor. ayrıca argümanınızı geçerli bulmuyorum. bir kişi 500k baytını sadece bir dize olarak saklayabilir ve sadece çılgın hızlı ve çok daha yaygın olan alt dizeleri döndürebilir.
kritzikratzi

6
@kritzikratzi - JDK7'den itibaren, String üzerindeki alt dize artık altta yatan diziyi paylaşmaz ve "çılgın hızlı" değildir. Alt dizenin uzunluğunda O (N) zaman alır ve her aradığınızda alttaki karakterlerin bir kopyasını oluşturur (bu yüzden çok fazla çöp).
BeeOnRope

@kritzikratzi Değişikliğin sebebinin, eğer kopya yapılmazsa, orijinal Dize'nin tüm alt dizelerin ömrü boyunca saklanacağına inanıyorum. Alt dizelerin genellikle orijinalin yalnızca küçük parçaları olduğu ve bunların nasıl kullanıldığına bağlı olarak süresiz olarak sürdüğü göz önüne alındığında, alt dizeler orijinal dizeden çok daha uzun süre kullanılıyorsa, bu genellikle daha fazla çöple sonuçlanır. İlginç bir alt, alt dizenin üst dize boyutuna oranına göre kopyalanıp kopyalanmayacağını belirlemek olabilir, ancak bunun için kendi CharSequenceuygulamanızı yuvarlamanız gerekir .
JAB

1
Belki de noktayı kaçırdım, ama bu cevap saçmalık. A CharSequencebir arayüzdür - tanım gereği, tartıştığınız uygulama detaylarının hiçbirine sahip değildir, çünkü kendi uygulaması yoktur . A String, arabirimi uygulayan birkaç somut sınıftan biridir CharSequence. Yani bir String olan bir CharSequence. Sen performans ayrıntılarını karşılaştırabilirsiniz Stringvs StringBuffervs StringBuilderdeğil CharSequence. “CharSequence kullanarak elde ettiğiniz kazançları işlemek” yazmak anlamsızdır.
Basil Bourque

7

Pratik Android kodunda ortaya çıkan bir sorun, bunları CharSequence.equals ile karşılaştırmanın geçerli olduğu, ancak amaçlandığı gibi çalışmadığıdır.

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

Karşılaştırma şu şekilde yapılmalıdır:

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

5

CharSequence

A CharSequencegerçek bir sınıf değil, bir arayüzdür. Bir arabirim, bir sınıfın arabirimi uygularsa içermesi gereken kurallar kümesidir (yöntemler). Android'de bir CharSequencemetin dizeleri türleri için bir şemsiye. İşte yaygın olanlardan bazıları:

(Bunlar arasındaki farklar hakkında daha fazla bilgiyi buradan edinebilirsiniz .)

Eğer bir CharSequencenesneniz varsa, o zaman bu aslında uygulanan sınıflardan birinin nesnesidir CharSequence. Örneğin:

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

Genel bir şemsiye tipine sahip olmanın faydası, CharSequencetek bir yöntemle birden fazla türü işleyebilmenizdir. Örneğin, CharSequencea parametresini alan bir yöntemim varsa , bir Stringveya a iletebilirim SpannableStringBuilderve her ikisini de işleyebilir.

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

sicim

A'nın Stringsadece bir tür olduğunu söyleyebilirsiniz CharSequence. Ancak, aksine CharSequence, gerçek bir sınıftır, böylece ondan nesne yapabilirsiniz. Böylece bunu yapabilirsiniz:

String myString = new String();

ama bunu yapamazsın:

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

Yana CharSequenceolduğunu kuralların sadece bir liste Stringuygundur, bunu yapabileceğini için:

CharSequence myString = new String();

Bu, bir yöntem a istediğinde CharSequenceona a vermekte fayda olduğu anlamına gelir String.

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

// ...

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

Ancak bunun tersi doğru değildir. Eğer yöntem bir Stringparametre alırsa , sadece genel olarak a olarak bilinen bir CharSequenceşeyi iletemezsiniz, çünkü aslında bir SpannableStringya da başka bir tür olabilir CharSequence.

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

// ...

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

0

CharSequencebir arayüzdür ve Stringuygular. Bir örneği başlatabilirsiniz, Stringancak bunu CharSequencebir arabirim olduğu için yapamazsınız . Diğer uygulamaları CharSequenceresmi Java web sitesinde bulabilirsiniz.


-4

CharSequence, String'i uygulayan okunabilir bir char değerleri dizisidir. 4 yöntemi vardır

  1. charAt (int dizini)
  2. uzunluğu ()
  3. subSequence (int başlangıç, int bitiş)
  4. toString ()

Lütfen belgelere bakın CharSequence belgeleri


6
CharSequenceuygulanmaz String. Ancak bunun tersi doğrudur.
seh

1
Lütfen bu saçma cevabı kaldırın
J. Doe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.