- Как мне заставить CaseInsensitiveString вести себя как String, чтобы вышеприведенный оператор был в порядке (с расширением String и без расширения)? Что такого в String, которое позволяет просто передавать его в таком виде? Насколько я понимаю, в Java нет понятия «конструктор копирования», верно?
Достаточно было сказано с первого момента. «Польский» является строковым литералом и не может быть назначен классу CaseInsentiviveString.
Теперь о второй точке
Хотя вы не можете создавать новые литералы, вы можете следовать первому пункту этой книги для «похожего» подхода, поэтому следующие утверждения верны:
// Lets test the insensitiveness
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;
// Effective Java Item 1: Consider providing static factory methods instead of constructors
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 );
}
// Class constructor: This creates a new instance each time it is invoked.
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 ) {
// Creating two different objects as in new String("Polish") == new String("Polish") is false
CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish");
CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish");
// references cis1 and cis2 points to differents objects.
// so the following is true
assert cis1 != cis2; // Yes they're different
assert cis1.equals(cis2); // Yes they're equals thanks to the equals method
// Now let's try the valueOf idiom
CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish");
CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish");
// References cis3 and cis4 points to same object.
// so the following is true
assert cis3 == cis4; // Yes they point to the same object
assert cis3.equals(cis4); // and still equals.
// Lets test the insensitiveness
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
// Futhermore
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 и верните оттуда соответствующий экземпляр.
Таким образом, оператор "==" возвращает true для двух ссылок на объекты, представляющих одинаковое значение .
Это полезно, когда подобные объекты используются очень часто, а создание затрат обходится дорого.
В документации строкового класса указано, что класс использует внутренний пул
Класс не завершен, некоторые интересные проблемы возникают, когда мы пытаемся просмотреть содержимое объекта при реализации интерфейса CharSequence, но этот код достаточно хорош, чтобы показать, как этот элемент в Книге может быть применен.
Важно отметить, что при использовании объекта internalPool ссылки не освобождаются и, следовательно, не подлежат сборке мусора, что может стать проблемой при создании большого количества объектов.
Он работает для класса String, поскольку интенсивно используется и пул состоит только из "интернированного" объекта.
Это хорошо работает и для булева класса, потому что есть только два возможных значения.
И, наконец, это также причина, по которой valueOf (int) в классе Integer ограничено значениями от -128 до 127 int.