- Jak sprawić, by CaseInsensitiveString zachowywał się jak String, aby powyższa instrukcja była w porządku (zi bez rozszerzenia String)? Co takiego jest w String, że można po prostu przekazać go tak dosłownie? Z mojego punktu widzenia w Javie nie ma koncepcji „konstruktora kopiującego”, prawda?
Dość już powiedziano od pierwszego punktu. „Polski” jest ciągiem znaków i nie można go przypisać do klasy CaseInsentiviveString.
Teraz o drugim punkcie
Chociaż nie możesz tworzyć nowych literałów, możesz postępować zgodnie z pierwszym punktem tej książki, aby zastosować „podobne” podejście, więc poniższe stwierdzenia są prawdziwe:
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
Oto kod.
C:\oreyes\samples\java\insensitive>type CaseInsensitiveString.java
import java.util.Map;
import java.util.HashMap;
public final class CaseInsensitiveString {
private static final Map<String,CaseInsensitiveString> innerPool
= new HashMap<String,CaseInsensitiveString>();
private final String s;
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 );
}
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();
}
// Przetestuj klasę za pomocą słowa kluczowego „assert”
public static void main( String [] args ) {
CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish");
CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish");
assert cis1 != cis2;
assert cis1.equals(cis2);
CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish");
CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish");
assert cis3 == cis4;
assert cis3.equals(cis4);
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
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>
Oznacza to, że należy utworzyć wewnętrzną pulę obiektów CaseInsensitiveString i stamtąd zwrócić odpowiednią instancję.
W ten sposób operator „==” zwraca prawdę dla dwóch odniesień do obiektów reprezentujących tę samą wartość .
Jest to przydatne, gdy podobne obiekty są używane bardzo często, a tworzenie kosztów jest kosztowne.
Dokumentacja klasy string stwierdza, że klasa używa puli wewnętrznej
Klasa nie jest kompletna, pojawiają się interesujące problemy, gdy próbujemy przejść przez zawartość obiektu podczas implementacji interfejsu CharSequence, ale ten kod jest wystarczająco dobry, aby pokazać, jak można zastosować ten element w Księdze.
Należy zauważyć, że przy użyciu obiektu internalPool odwołania nie są zwalniane, a tym samym nie mogą być usuwane z pamięci, co może stać się problemem, jeśli zostanie utworzonych wiele obiektów.
Działa dla klasy String, ponieważ jest intensywnie użytkowana, a pula składa się wyłącznie z obiektu „internowanego”.
Działa dobrze również dla klasy Boolean, ponieważ są tylko dwie możliwe wartości.
I wreszcie jest to również powód, dla którego wartość valueOf (int) w klasie Integer jest ograniczona do -128 do 127 wartości int.