Programmering

Streng sammenligninger i Java

I Java er String klasse innkapsler en rekke røye. Enkelt sagt, String er en rekke tegn som brukes til å komponere ord, setninger eller andre data du vil ha.

Innkapsling er et av de kraftigste begrepene innen objektorientert programmering. På grunn av innkapsling trenger du ikke vite det hvordan String-klassen fungerer; du trenger bare å vite hva metoder å bruke på grensesnittet.

Når du ser på String klasse i Java, kan du se hvordan matrisen av røye er innkapslet:

 public String (char value []) {this (value, 0, value.length, null); } 

For å forstå innkapsling bedre, bør du vurdere et fysisk objekt: en bil. Trenger du å vite hvordan bilen fungerer under panseret for å kjøre den? Selvfølgelig ikke, men du trenger å vite hva grensesnittene til bilen gjør: ting som gasspedal, bremser og ratt. Hver av disse grensesnittene støtter visse handlinger: akselerere, bremse, vri til venstre, ta til høyre. Det er det samme i objektorientert programmering.

Min første blogg i Java Challengers serien introduserte metoden overbelastning, som er en teknikk den String klasse bruker mye. Overbelastning kan gjøre klassene dine veldig fleksible, inkludert String:

 public String (String original) {} public String (char value [], int offset, int count) {} public String (int [] codePoints, int offset, int count) {} public String (byte bytes [], int offset , int length, String charsetName) {} // Og så videre ... ... 

Snarere enn å prøve å forstå hvordan String klassen fungerer, vil denne Java Challenger hjelpe deg med å forstå hva det gjør og hvordan å bruke den i koden din.

Hva er et strengbasseng?

String er muligens den mest brukte klassen i Java. Hvis et nytt objekt ble opprettet i hukommelsesbunken hver gang vi brukte en String, vi vil kaste bort mye minne. De String basseng løser dette problemet ved å lagre bare ett objekt for hver String verdi, som vist nedenfor.

Rafael Chinelato Del Nero

Selv om vi opprettet en String variabel for hertug og JuggyStrings, bare to objekter blir opprettet og lagret i minnesbunken. For bevis, se på følgende kodeeksempel. (Husk at “==”-Operatør i Java brukes til å sammenligne to objekter og avgjøre om de er de samme.)

 String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println (juggy == anotherJuggy); 

Denne koden kommer tilbake ekte fordi de to Strings peker på det samme objektet i String basseng. Verdiene deres er de samme.

Et unntak: Den ‘nye’ operatøren

Se nå på denne koden - den ser ut som den forrige prøven, men det er en forskjell.

 String hertug = ny streng ("hertug"); String anotherDuke = ny streng ("hertug"); System.out.println (hertug == anotherDuke); 

Basert på forrige eksempel, kan du tro at denne koden ville komme tilbake ekte, men det er faktisk falsk. Legge til ny operatøren tvinger etableringen av en ny String i minnehaugen. Dermed vil JVM lage to forskjellige objekter.

Innfødte metoder

EN innfødt metode i Java er en metode som skal kompileres ved hjelp av C-språket, vanligvis med det formål å manipulere minne og optimalisere ytelsen.

Strengbassenger og intern () -metoden

Å lagre en String i String basseng, bruker vi en teknikk som heter String interning. Her er hva Javadoc forteller oss om turnuskandidat() metode:

 / ** * Returnerer en kanonisk representasjon for strengobjektet. * * Et basseng med strenger, først tomt, vedlikeholdes privat av * klassen {@code String}. * * Når internmetoden påkalles, hvis bassenget allerede inneholder en * streng lik dette {@code String} -objektet som bestemt av * metoden {@link #equals (Object)}, er strengen fra bassenget returnert. Ellers blir dette {@code String} -objektet lagt til i * bassenget, og en referanse til dette {@code String} -objektet returneres. * * Det følger at for to strenger {@code s} og {@code t}, er * {@code s.intern () == t.intern ()} {@code true} * hvis og bare hvis { @code s.equals (t)} er {@code true}. * * Alle bokstavelige strenger og strengverdige konstante uttrykk er * internert. Strengbokstaver er definert i avsnitt 3.10.5 i * Java ™ språkspesifikasjonen. * * @ returnerer en streng som har samme innhold som denne strengen, men som * garantert kommer fra en samling unike strenger. * @jls 3.10.5 String Literals * / public native String intern (); 

De turnuskandidat() metoden brukes til å lagre Strings i en String basseng. Først verifiserer det om String du har opprettet, eksisterer allerede i bassenget. Hvis ikke, skaper det et nytt String i bassenget. Bak kulissene, logikken til String pooling er basert på Flyweight-mønsteret.

Legg merke til hva som skjer når vi bruker ny nøkkelord for å tvinge opprettelsen av to Strings:

 String hertug = ny streng ("hertug"); String duke2 = new String ("duke"); System.out.println (hertug == duke2); // Resultatet vil være falskt her System.out.println (duke.intern () == duke2.intern ()); // Resultatet vil være sant her 

I motsetning til forrige eksempel med ny nøkkelord, i dette tilfellet viser sammenligningen seg å være sant. Det er fordi bruk av turnuskandidat() metoden sikrer Strings lagres i bassenget.

Ligner metode med String-klassen

De er lik() metoden brukes til å verifisere om tilstanden til to Java-klasser er den samme. Fordi er lik() er fra Gjenstand klasse, arver hver Java-klasse den. Men er lik() metoden må overstyres for å få den til å fungere skikkelig. Selvfølgelig, String overstyrer er lik().

Ta en titt:

 offentlig boolsk er lik (Object anObject) {if (this == anObject) {return true; } if (anObject instance of String) {String aString = (String) anObject; hvis (coder () == aString.coder ()) {return erLatin1 ()? StringLatin1.equals (verdi, aString.value): StringUTF16.equals (verdi, aString.value); }} returner falsk; } 

Som du kan se, er tilstanden til String klasseverdien må være er lik() og ikke objektreferansen. Det spiller ingen rolle om objektreferansen er annerledes; tilstanden til String vil bli sammenlignet.

De vanligste strengmetodene

Det er bare en siste ting du trenger å vite før du tar String sammenligningsutfordring. Vurder disse vanlige metodene for String klasse:

 // Fjerner mellomrom fra kantlinjene () // Får en delstreng ved å indeksere delstreng (int beginIndex, int endIndex) // Returnerer tegnlengden på strenglengden () // Erstatter streng, regex kan brukes. replaceAll (String regex, String replacement) // Bekrefter om det er en spesifisert CharSequence i Strengen inneholder (CharSequences) 

Ta String sammenligningsutfordringen!

La oss prøve det du har lært om String klasse i en rask utfordring.

For denne utfordringen vil du sammenligne et antall Strings bruker konseptene vi har utforsket. Ser du på koden nedenfor, kan du bestemme den endelige verdien av hver resultater variabel?

 public class ComparisonStringChallenge {public static void main (String ... doYourBest) {String result = ""; resultat + = "powerfulCode" .trim () == "powerfulCode"? "0": "1"; resultat + = "FlexibleCode" == "FlexibleCode"? "2": "3"; resultat + = ny streng ("gjørDinBest") == ny streng ("gjørDinBest")? "4": "5"; resultat + = ny streng ("noBugsProject"). likestillinger ("noBugsProject")? "6": "7"; resultat + = ny streng ("breakYourLimits"). praktikant () == ny streng ("breakYourLimits"). praktikant ()? "8": "9"; System.out.println (resultat); }} 

Hvilken utgang representerer den endelige verdien av resultatvariabelen?

EN: 02468

B: 12469

C: 12579

D: 12568

Sjekk svaret ditt her.

Hva skjedde nå? Forstå strengadferd

I den første linjen i koden ser vi:

 resultat + = "powerfulCode" .trim () == "powerfulCode"? "0": "1"; 

Selv om String vil være den samme etter listverk() metoden påberopes, String“Kraftig kode” var annerledes i begynnelsen. I dette tilfellet er sammenligningen falsk, fordi når listverk() metoden fjerner mellomrom fra grensene den tvinger etableringen av et nytt String med den nye operatøren.

Deretter ser vi:

 resultat + = "FlexibleCode" == "FlexibleCode"? "2": "3"; 

Ingen mysterium her, den Strings er de samme i String basseng. Denne sammenligningen kommer tilbake ekte.

Deretter har vi:

 resultat + = ny streng ("gjørDinBest") == ny streng ("gjørDinBest")? "4": "5"; 

Bruker ny reservert nøkkelord tvinger etableringen av to nye Strings, enten de er like eller ikke. I dette tilfellet vil sammenligningen være falsk selv om String verdiene er de samme.

Neste er:

 resultat + = ny streng ("noBugsProject"). likestillinger ("noBugsProject")? "6": "7"; 

Fordi vi har brukt er lik() metoden, verdien av String vil bli sammenlignet og ikke objektforekomsten. I så fall spiller det ingen rolle om objektene er forskjellige fordi verdien blir sammenlignet. Denne sammenligningen kommer tilbake ekte.

Til slutt har vi:

 resultat + = ny streng ("breakYourLimits"). praktikant () == ny streng ("breakYourLimits"). praktikant ()? "8": "9"; 

Som du har sett før, turnuskandidat() metoden setter String i String basseng. Både Strings peker på det samme objektet, så i dette tilfellet er sammenligningen ekte.

Videoutfordring! Feilsøking av streng sammenligninger

Feilsøking er en av de enkleste måtene å fullt ut absorbere programmeringskonsepter samtidig som du forbedrer koden din. I denne videoen kan du følge med mens jeg feilsøker og forklarer Java Strings-utfordringen:

Vanlige feil med strenger

Det kan være vanskelig å vite om to Strings peker på det samme objektet, spesielt når Strings inneholder samme verdi. Det hjelper å huske at bruk av det reserverte nøkkelordet ny resulterer alltid i at et nytt objekt blir opprettet i minnet, selv om verdiene er de samme.

Ved hjelp av String metoder for å sammenligne Gjenstand referanser kan også være vanskelig. Nøkkelen er, hvis metoden endrer noe i Stringvil objektreferansene være forskjellige.

Noen få eksempler for å avklare:

 System.out.println ("hertug" .trim () == "hertug" .trim ()) ;; 

Denne sammenligningen vil være sant fordi listverk() metoden genererer ikke en ny String.

 System.out.println ("hertug" .trim () == "hertug" .trim ()); 

I dette tilfellet den første listverk() metoden vil generere en ny String fordi metoden vil utføre sin handling, så referansene vil være forskjellige.

Endelig når listverk() utfører sin handling, skaper den en ny String:

 // Implementering av trimmetoden i String-klassen new String (Arrays.copyOfRange (val, index, index + len), LATIN1); 

Hva du skal huske om strenger

  • Strings er uforanderlige, så a StringTilstand kan ikke endres.
  • For å spare minne holder JVM Strings i en String basseng. Når en ny String blir opprettet, sjekker JVM verdien og peker den mot et eksisterende objekt. Hvis det ikke er noe String med den verdien i bassenget, oppretter JVM en ny String.
  • Bruker == operatøren sammenligner objektreferansen. Bruker er lik() metoden sammenligner verdien av String. Den samme regelen blir brukt på alle objekter.
  • Når du bruker ny operatør, en ny String vil bli opprettet i String basseng selv om det er et String med samme verdi.

 

Fasit

Svaret på denne Java-utfordreren er alternativ D. Utgangen ville være 12568.

Denne historien, "String comparisons in Java" ble opprinnelig utgitt av JavaWorld.