- Como faço para que CaseInsensitiveString se comporte como String para que a declaração acima esteja ok (com e sem extensão de String)? O que há em String que torna ok apenas ser capaz de passar um literal como esse? Do meu entendimento, não existe um conceito de "construtor de cópia" em Java, certo?
Já foi dito o suficiente desde o primeiro ponto. "Polish" é um literal de string e não pode ser atribuído à classe CaseInsentiviveString.
Agora sobre o segundo ponto
Embora você não possa criar novos literais, você pode seguir o primeiro item desse livro para uma abordagem "semelhante", de modo que as seguintes afirmações sejam verdadeiras:
CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg");
CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG");
assert cis5 == cis6;
assert cis5.equals(cis6);
Aqui está o código.
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();
}
// Teste a classe usando a palavra-chave "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>
Ou seja, crie um pool interno de objetos CaseInsensitiveString e retorne a instância correspondente a partir daí.
Desta forma, o operador "==" retorna verdadeiro para referências de dois objetos que representam o mesmo valor .
Isso é útil quando objetos semelhantes são usados com muita frequência e a criação de custos é cara.
A documentação da classe string afirma que a classe usa um pool interno
A aula não está completa, alguns problemas interessantes surgem quando tentamos percorrer o conteúdo do objeto na implementação da interface CharSequence, mas este código é bom o suficiente para mostrar como aquele item do livro pode ser aplicado.
É importante notar que usando o objeto internalPool , as referências não são liberadas e, portanto, não podem ser coletadas como lixo, e isso pode se tornar um problema se muitos objetos forem criados.
Funciona para a classe String porque é usada intensamente e o pool é constituído apenas de objeto "internado".
Também funciona bem para a classe Booleana, porque existem apenas dois valores possíveis.
E, finalmente, essa também é a razão pela qual valueOf (int) na classe Integer está limitado a -128 a 127 valores int.