- Как заставить CaseInsensitiveString вести себя как String, чтобы приведенный выше оператор был в порядке (с расширением String и без него)? Что такого в String, что позволяет просто передать ему такой литерал? Насколько я понимаю, в Java нет концепции "конструктора копирования", верно?
С самого начала было сказано достаточно. «Польский» - это строковый литерал, и его нельзя присвоить классу CaseInsentiviveString.
Теперь о втором пункте
Хотя вы не можете создавать новые литералы, вы можете следовать первому пункту этой книги для «аналогичного» подхода, поэтому следующие утверждения верны:
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
Вот код.
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();
}
// Тестируем класс с помощью ключевого слова 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>
То есть создайте внутренний пул объектов CaseInsensitiveString и верните оттуда соответствующий экземпляр.
Таким образом, оператор "==" возвращает истину для двух ссылок на объекты, представляющих одно и то же значение. .
Это полезно, когда похожие объекты используются очень часто и создание затрат обходится дорого.
В документации по строковому классу указано, что класс использует внутренний пул.
Класс не завершен, некоторые интересные проблемы возникают, когда мы пытаемся пройтись по содержимому объекта при реализации интерфейса CharSequence, но этот код достаточно хорош, чтобы показать, как этот элемент в Книге может быть применен.
Важно отметить, что при использовании объекта internalPool ссылки не освобождаются и, следовательно, не подлежат сборке мусора, и это может стать проблемой, если создается много объектов.
Он работает для класса String, потому что он интенсивно используется, а пул состоит только из «интернированных» объектов.
Это хорошо работает и для логического класса, потому что есть только два возможных значения.
И, наконец, это также причина, по которой valueOf (int) в классе Integer ограничено от -128 до 127 значений int.