Diferența exactă între CharSequence și String în java [duplicate] (Programare, Java, String, Secvență De Caractere)

Amith a intrebat.

Am citit acest post anterior. Poate cineva să spună care este diferența exactă între CharSequence și String este, în afară de faptul că String implementează CharSequence și că String este o secvență de caractere? De exemplu:

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

Ce se întâmplă atunci când „hello” este atribuit la obj și din nou la str ?

Comentarii

  • Acest lucru va suna foarte RTFMish, dar este un sfat sincer: poate fi foarte interesant și o experiență de învățare să te uiți tu însuți la codul sursă pentru String –  > Por Miquel.
  • Unde puteți găsi codul sursă Java? Credeam că totul este proprietar? –  > Por aaronsnoswell.
  • @aaronsnoswell: OpenJDK este open source. Puteți găsi o versiune a String clasă la hg.openjdk.java.net/jdk7u/jdk7u/jdk/jdk/file/6069fe8ffead/src/share/…. Dar chiar și înainte de asta, JDK-urile Sun JDK-uri obișnuiau să vină cu un fișier numit src.zip care conținea o mare parte din codul sursă. Consultarea acelui cod era posibilă și utilă, deși modificarea lui era probabil o altă problemă, din punct de vedere al licenței. –  > Por MvG.
  • În ceea ce privește codul sursă, mai multe companii oferă acces, prin intermediul propriilor site-uri web, la diverse proiecte open source, inclusiv OpenJDK. Pur și simplu folosiți un motor de căutare pentru o interogare de tipul „java string class source code” pentru a obține mai multe rezultate privind acești furnizori. –  > Por Basil Bourque.
  • Similar cu: De ce StringBuilder când există String? –  > Por Basil Bourque.
8 răspunsuri
MvG

Diferențe generale

Există mai multe clase care implementează CharSequence interfața în afară de String. Printre acestea se numără

  • StringBuilder pentru secvențe de caractere de lungime variabilă care pot fi modificate
  • CharBuffer pentru secvențe de caractere de lungime fixă de nivel scăzut care pot fi modificate

Orice metodă care acceptă un CharSequence poate funcționa cu toate acestea la fel de bine. Orice metodă care acceptă numai a String va necesita conversie. Prin urmare, utilizarea CharSequence ca tip de argument în toate locurile în care nu vă pasă de elementele interne este prudent. Cu toate acestea, ar trebui să utilizați String ca tip de retur dacă returnezi efectiv un String, deoarece astfel se evită posibilele conversii ale valorilor returnate dacă metoda apelantă necesită de fapt un tip de tip String.

Rețineți, de asemenea, că hărțile ar trebui să utilizeze String ca tip de cheie, nu CharSequence, deoarece cheile hărților nu trebuie să se schimbe. Cu alte cuvinte, uneori, natura imuabilă a String este esențială.

Fragment de cod specific

În ceea ce privește codul pe care l-ați lipit: compilați-l pur și simplu și aruncați o privire la codul de byte JVM folosind javap -v. Acolo veți observa că atât obj și str sunt referințe la același obiect constant. Ca un String este imuabil, acest tip de partajare este în regulă.

Adresa + al operatorului String este compilat sub forma unor invocări ale diferitelor StringBuilder.append apeluri. Astfel, este echivalent cu

System.out.println(
  (new StringBuilder())
  .append("output is : ")
  .append((Object)obj)
  .append(" ")
  .append(str)
  .toString()
)

Trebuie să mărturisesc că sunt puțin surprins că compilatorul meu javac 1.6.0_33 compilează + obj folosind StringBuilder.append(Object) în loc de StringBuilder.append(CharSequence). Primul implică probabil un apel la toString() a obiectului, în timp ce al doilea ar trebui să fie posibil într-un mod mai eficient. Pe de altă parte, String.toString() returnează pur și simplu valoarea String însuși, deci nu există o mică penalizare în acest sens. Așadar, StringBuilder.append(String) ar putea fi mai eficient cu aproximativ o invocare a unei metode.

Basil Bourque

tl;dr

Una este o interfață (CharSequence), în timp ce cealaltă este o implementare concretă a acelei interfețe (String).

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

La fel ca ArrayList este un List, , și HashMap este un Map, , la fel și String este a CharSequence.

Ca interfață, în mod normal se utilizează CharSequence ar fi mai des întâlnită decât String, , dar o istorie întortocheată a făcut ca interfața să fie definită ani după implementarea. Prin urmare, în API-urile mai vechi vedem adesea String în timp ce în API-urile mai noi avem tendința de a vedea CharSequence utilizate pentru a defini argumentele și tipurile de returnare.

Detalii

În zilele noastre știm că, în general, un API/framework ar trebui să se concentreze în primul rând pe exportul de interfețe și în al doilea rând pe clasele concrete. Dar nu întotdeauna am știut atât de bine această lecție.

Site-ul String class a apărut prima dată în Java. Abia mai târziu au plasat o interfață frontală, CharSequence.

Istoria Twisted

Un pic de istorie ar putea ajuta la înțelegere.

La începuturile sale, Java a fost lansat în grabă pe piață cu puțin înaintea timpului său, din cauza maniei Internetului/Web care anima industria. Unele biblioteci nu au fost atât de bine gândite pe cât ar fi trebuit să fie. Manipularea șirurilor de caractere a fost unul dintre aceste domenii.

De asemenea, Java a fost una dintre primele aplicații orientate spre producție, orientate spre non-academie, și a fost una dintre primele Programare orientată pe obiecte (OOP) (OOP). Singurele implementări reușite de OOP din lumea reală înainte de aceasta au fost unele versiuni limitate ale SmallTalk, , apoi Objective-C cu NeXTSTEP/OpenStep. Așadar, mai erau multe lecții practice de învățat.

Java a început cu String și clasa StringBuffer clasă. Dar aceste două clase nu erau legate între ele, nu erau legate între ele prin moștenire și nici prin interfață. Mai târziu, echipa Java a recunoscut că ar fi trebuit să existe o legătură unificatoare între implementările legate de șiruri de caractere pentru a le face interschimbabile. În Java 4, echipa a adăugat în Java 4 elementul CharSequence și a implementat retroactiv această interfață pe String și String Buffer, precum și adăugarea unei alte implementări CharBuffer. Mai târziu, în Java 5, au adăugat StringBuilder, , practic o versiune nesincronizată și, prin urmare, ceva mai rapidă a lui StringBuffer.

Așadar, aceste clase orientate pe șiruri de caractere sunt un pic cam încurcate și puțin confuze pentru a învăța despre ele. Multe biblioteci și interfețe au fost construite pentru a prelua și returna String obiecte. În zilele noastre, astfel de biblioteci ar trebui, în general, să fie construite pentru a aștepta CharSequence. Dar (a) String pare să domine în continuare spațiul mental și (b) pot exista unele probleme tehnice subtile atunci când se amestecă diversele CharSequence implementări. Cu o viziune retrospectivă de 20/20 putem vedea că toate aceste lucruri legate de șiruri de caractere ar fi putut fi gestionate mai bine, dar iată-ne ajunși aici.

În mod ideal, Java ar fi început cu o interfață și/sau o superclasă care să fie utilizată în multe locuri în care acum folosim String, , la fel cum folosim Collection sau List în locul interfețelor ArrayList sau LinkedList implementări.

Interfață față de clasă

Diferența esențială în ceea ce privește CharSequence este că este o interfață, și nu o implementare. Aceasta înseamnă că nu puteți instanția direct un CharSequence. Mai degrabă instanți una dintre clasele care implementează acea interfață.

De exemplu, aici avem x care arată ca o CharSequence dar dedesubt este de fapt o clasă StringBuilder obiect.

CharSequence x = new StringBuilder( "dog" );  // Looks like a `CharSequence` but is actually a `StringBuilder` instance.

Acest lucru devine mai puțin evident atunci când se utilizează un literal String. Rețineți că, atunci când vedeți un cod sursă care conține doar ghilimele în jurul caracterelor, compilatorul îl traduce într-un obiect String.

CharSequence y = "cat";  // Looks like a `CharSequence` but is actually a `String` instance.

Literal versus constructor

Există câteva diferențe subtile între "cat" și new String("cat") discutate în această altă Întrebare, dar care sunt irelevante aici.

Diagrama clasei

Această diagramă de clasă vă poate ajuta să vă ghidați. Am notat versiunea de Java în care au apărut pentru a demonstra cât de multe schimbări au trecut prin aceste clase și interfețe.

Blocuri de text

În afară de adăugarea mai multor Unicode caractere, inclusiv o multitudine de emoji, , în ultimii ani nu s-au schimbat prea multe în Java pentru lucrul cu textul. Până la blocurile de text.

Blocurile de text sunt un nou mod de a gestiona mai bine plictiseala literali de șiruri de caractere cu mai multe linii sau de eliminare a caracterelor. Acest lucru ar face mult mai comodă scrierea de șiruri de cod încorporate, cum ar fi HTML, XML, SQL sau JSON.

Pentru a cita JEP 378:

Un bloc de text este un literal de șir de caractere pe mai multe linii care evită necesitatea majorității secvențelor de evacuare, formatează automat șirul într-un mod previzibil și oferă dezvoltatorului controlul asupra formatului atunci când dorește.

Caracteristica blocurilor de text face nu introduce o nouă tip de date. Blocurile de text reprezintă doar o nouă sintaxă pentru scrierea unui fișier String literal. Un bloc de text produce un String obiect, la fel ca și sintaxa literalului convențional. Un bloc de text produce un obiect String care este, de asemenea, un obiect CharSequence obiect, așa cum s-a discutat mai sus.

Exemplu SQL

Pentru a cita din nou JSR 378…

Utilizarea de literali de șir de caractere „unidimensionali”.

String query = "SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
" +
               "WHERE "CITY" = 'INDIANAPOLIS'
" +
               "ORDER BY "EMP_ID", "LAST_NAME";
";

Utilizarea unui bloc de text „bidimensional”.

String query = """
               SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
               WHERE "CITY" = 'INDIANAPOLIS'
               ORDER BY "EMP_ID", "LAST_NAME";
               """;

Blocurile de text se găsesc în Java 15 și ulterior, conform JEP 378: Blocuri de text.

Prezentat pentru prima dată în Java 13, în cadrul JEP 355: Blocuri de text (Previzualizare). Apoi a fost previzualizat din nou în Java 14, la rubrica JEP 368: Blocuri de text (a doua previzualizare).

Acest efort a fost precedat de JEP 326: Literale de șiruri de caractere brute (Previzualizare). Conceptele au fost reelaborate pentru a produce Blocuri de text în locul acesteia.

Comentarii

  • vechea școală bună –  > Por Yugerten.
  • Minunat , am citit alte răspunsuri și mă gândeam cum de știe tipul ăla atât de multe , toate sunt lungi și bine explicate ai găsit o modalitate de a descărca informații în creierul tău 🙂 –  > Por Abhinav Chauhan.
Francisco Spaeth

CharSequence este un contract (interfață), iar String este un implementare a acestui contract.

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

Adresa documentația pentru CharSequence este:

O CharSequence este o secvență lizibilă de valori char. Această interfață oferă acces uniform, numai pentru citire, la mai multe tipuri diferite de secvențe de caractere. O valoare char reprezintă un caracter din planul multilingv de bază (BMP) sau un surogat. Pentru detalii, consultați Reprezentarea caracterelor Unicode.

asylias

în afară de faptul că String implementează CharSequence și că String este o secvență de caractere.

În codul dvs. se întâmplă mai multe lucruri:

CharSequence obj = "hello";

Se creează un String literal, "hello", , care este un String obiect. Fiind un String, , care implementează CharSequence, , este, de asemenea, un CharSequence. (puteți citi această postare despre codarea la interfață, de exemplu).

Următoarea linie:

String str = "hello";

este un pic mai complexă. String literalele în Java sunt păstrate într-un pool (interned), astfel că "hello" de pe această linie este același obiect (identitate) ca și "hello" de pe prima linie. Prin urmare, această linie nu face decât să atribuie același String literal la str.

În acest moment, atât obj și str sunt referințe la String literal "hello" și, prin urmare, sunt equals, , == și sunt ambele a String și a CharSequence.

Vă sugerez să testați acest cod, arătând în acțiune ceea ce tocmai am scris:

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));
}

Mark Bramnik

Știu că este cam evident, dar CharSequence este o interfață, în timp ce String este o clasă concretă 🙂

java.lang.String este o implementare a acestei interfețe…

Andreas Johansson

Din API-ul Java al CharSequence:

O CharSequence este o secvență lizibilă de caractere. Această interfață oferă acces uniform, numai pentru citire, la multe tipuri diferite de secvențe de caractere.

Această interfață este apoi utilizată de String, , CharBuffer și StringBuffer pentru a păstra consecvența pentru toate denumirile de metode.

Patrick Campbell

Luați în considerare UTF-8. În UTF-8, punctele de cod Unicode sunt construite din unul sau mai mulți octeți. O clasă care încapsulează o matrice de octeți UTF-8 poate implementa interfața CharSequence, dar în mod sigur nu este un String. În mod cert, nu puteți trece o matrice de octeți UTF-8 acolo unde se așteaptă un String, dar cu siguranță puteți trece o clasă de înveliș UTF-8 care implementează CharSequence atunci când contractul este relaxat pentru a permite o CharSequence. În cadrul proiectului meu, dezvolt o clasă numită CBTF8Field (Compressed Binary Transfer Format – Eight Bit) pentru a asigura compresia datelor pentru xml și încerc să folosesc interfața CharSequence pentru a implementa conversiile de la matrice de octeți CBTF8 la/de la matrice de caractere (UTF-16) și matrice de octeți (UTF-8).

Motivul pentru care am venit aici a fost acela de a obține o înțelegere completă a contractului subsequence.

Doszi89

În charSequence nu aveți metode foarte utile care sunt disponibile pentru String. Dacă nu vrei să te uiți în documentație, tastează: obj.și str.

și vezi ce metode îți oferă compilatorul tău. Aceasta este diferența de bază pentru mine.