- Wie mache ich CaseInsensitiveString so, dass es sich wie String verhält, sodass die obige Anweisung in Ordnung ist (mit und ohne Erweiterung von String)? Was ist es an String, das es in Ordnung macht, ihm einfach so ein Literal zu übergeben? Meines Wissens nach gibt es in Java kein "Kopierkonstruktor"-Konzept, oder?
Vom ersten Punkt wurde genug besprochen. "Polish" ist ein Zeichenkettenliteral und kann der Klasse CaseInsentiviveString nicht zugewiesen werden.
Nun zum zweiten Punkt
Auch wenn Sie keine neuen Literale erstellen können, können Sie den ersten Punkt dieses Buchs für einen "ähnlichen" Ansatz verwenden, damit die folgenden Aussagen wahr sind:
// Testen wir die Unempfindlichkeit
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
Hier ist der Code.
C:\oreyes\samples\java\insensitive>type CaseInsensitiveString.java
import java.util.Map;
import java.util.HashMap;
public final class CaseInsensitiveString {
private static final Map innerPool
= new HashMap();
private final String s;
// Effektiver Java-Element 1: Erwägen Sie die Bereitstellung von statischen Fabrikmethode anstelle von Konstruktoren
public static CaseInsensitiveString valueOf( String s ) {
if ( s == null ) {
return null;
}
String value = s.toLowerCase();
if ( !CaseInsensitiveString.innerPool.containsKey( value ) ) {
CaseInsensitiveString.innerPool.put( value , new CaseInsensitiveString( value ) );
}
return CaseInsensitiveString.innerPool.get( value );
}
// Klassenkonstruktor: Dies erzeugt bei jedem Aufruf eine neue Instanz.
public CaseInsensitiveString(String s){
if (s == null) {
throw new NullPointerException();
}
this.s = s.toLowerCase();
}
public boolean equals( Object other ) {
if ( other instanceof CaseInsensitiveString ) {
CaseInsensitiveString otherInstance = ( CaseInsensitiveString ) other;
return this.s.equals( otherInstance.s );
}
return false;
}
public int hashCode(){
return this.s.hashCode();
}
// Testen Sie die Klasse mit dem "assert" Schlüsselwort
public static void main( String [] args ) {
// Zwei verschiedene Objekte erstellen, da bei neuen String("Polish") == new String("Polish") falsch ist
CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish");
CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish");
// Verweise cis1 und cis2 deuten auf unterschiedliche Objekte.
// also folgendes ist wahr
assert cis1 != cis2; // Ja, sie sind unterschiedlich
assert cis1.equals(cis2); // Ja, sie sind gleich dank der equals Methode
// Jetzt probieren wir das valueOf-Idiom aus
CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish");
CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish");
// Verweise cis3 und cis4 deuten auf dasselbe Objekt.
// also folgendes ist wahr
assert cis3 == cis4; // Ja, sie zeigen auf dasselbe Objekt
assert cis3.equals(cis4); // und immer noch gleich.
// Testen wir die Unempfindlichkeit
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
// Außerdem
CaseInsensitiveString cis7 = CaseInsensitiveString.valueOf("SomethinG");
CaseInsensitiveString cis8 = CaseInsensitiveString.valueOf("someThing");
assert cis8 == cis5 && cis7 == cis6;
assert cis7.equals(cis5) && cis6.equals(cis8);
}
}
C:\oreyes\samples\java\insensitive>javac CaseInsensitiveString.java
C:\oreyes\samples\java\insensitive>java -ea CaseInsensitiveString
C:\oreyes\samples\java\insensitive>
Dadurch wird ein interner Pool von CaseInsensitiveString-Objekten erstellt und die entsprechende Instanz von dort zurückgegeben.
Auf diese Weise gibt der "==" Operator true zurück, wenn zwei Objektreferenzen den gleichen Wert darstellen.
Dies ist nützlich, wenn ähnliche Objekte sehr häufig verwendet werden und die Erstellungskosten hoch sind.
Die String-Klasse-Dokumentation besagt, dass die Klasse einen [internen Pool](http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()) verwendet
Die Klasse ist nicht vollständig, einige interessante Probleme entstehen, wenn wir versuchen, den Inhalt des Objekts beim Implementieren des CharSequence-Interface zu durchlaufen, aber dieser Code zeigt gut, wie das Element in dem Buch angewendet werden könnte.
Es ist wichtig zu beachten, dass durch die Verwendung des internalPool Objekts die Referenzen nicht freigegeben werden und somit nicht sammelbar sind, was zu einem Problem werden kann, wenn viele Objekte erstellt werden.
Es funktioniert für die String-Klasse, weil sie intensiv verwendet wird und der Pool nur aus "interned" Objekten besteht.
Es funktioniert auch gut für die Boolean-Klasse, da es nur zwei mögliche Werte gibt.
Und schließlich ist das auch der Grund, warum valueOf(int) in der Klasse Integer auf -128 bis 127 int-Werte beschränkt ist.
2 Stimmen
String str1 = "foo"; String str2 = "foo"; Beide str1 und str2 gehören zum selben String-Objekt, "foo", da Java Strings im StringPool verwaltet, sodass eine neue Variable auf denselben String verweist und nicht einen anderen erstellt, sondern den bereits im StringPool vorhandenen zuweist. Aber wenn wir dies tun: String str1 = new String("foo"); String str2 = new String("foo"); Hier gehören sowohl str1 als auch str2 zu verschiedenen Objekten, da new String() zwangsläufig ein neues String-Objekt erstellt.