Strings Java: "String s = new String ("silly");"
String s = new String("silly");
porque cria objectos desnecessários String
. Mas em vez disso deve ser escrito assim:
String s = "No longer silly";
Está bem, até agora...No entanto, dada esta classe:
public final class CaseInsensitiveString {
private String s;
public CaseInsensitiveString(String s) {
if (s == null) {
throw new NullPointerException();
}
this.s = s;
}
:
:
}
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
-
Porque é que a primeira declaração está bem? Não devia ser?
CaseInsensitiveString cis = "Polish";
Como faço para que
CaseInsensitiveString
me comporte comoString
de modo que a declaração acima está OK (com e sem estenderString
)? O que é que tem o String que faz com que seja bom apenas ser capaz de passá-lo um literal como esse? Pelo que sei, não há nenhum conceito de" construtor de cópias " em Java?
23 answers
String
é uma classe especial embutida da língua. É apenas para a classe String
em que você deve evitar dizer
String s = new String("Polish");
Porque o literal "Polish"
já é do tipo String
, e estás a criar um objecto extra desnecessário. Para qualquer outra classe, dizendo:
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
É a coisa certa (e única, neste caso) a fazer.
Eu acredito que o principal benefício de usar a forma literal (ou seja, "foo" ao invés de Nova Cadeia ("foo")) é que todos os literais de cadeia são 'internados' pelo VM. Em outras palavras, ele é adicionado a um pool tal que qualquer outro código que cria a mesma string irá usar a String agregada ao invés de criar uma nova instância.
Para ilustrar, o seguinte código irá imprimir verdadeiro para a primeira linha, mas falso para a Segunda:
System.out.println("foo" == "foo");
System.out.println(new String("bar") == new String("bar"));
As cordas são tratadas um pouco especialmente em java, são imutáveis, por isso é seguro para elas serem tratadas pela contagem de referências.
Se escrever
String s = "Polish";
String t = "Polish";
Então s e t realmente se referem ao mesmo objeto, E s==t retornará verdadeiro, pois "==" para objetos lidos "é o mesmo objeto" (ou pode, de qualquer forma, eu"não tenho certeza se isso é parte da linguagem spec real ou simplesmente um detalhe da implementação do compilador-então talvez não seja seguro confiar nisso) .
Se escrever
String s = new String("Polish");
String t = new String("Polish");
Então s!=t(porque você criou explicitamente uma nova string) embora S. igual a (t) irá retornar true (porque string adiciona este comportamento a igual).
A coisa que queres escrever,
CaseInsensitiveString cis = "Polish";
Não pode funcionar porque você está pensando que as citações são algum tipo de construtor de curto-circuito para o seu objeto, quando na verdade isso só funciona para java Velho e simples.idioma.Cadeia.
String s1="foo";
O Literal vai para a piscina e o s1 vai referir-se.
String s2="foo";
Desta vez ele vai verificar "Foo" literal já está disponível em StringPool ou não como agora ele existe então s2 vai se referir ao mesmo literal.
String s3=new String("foo");
" Foo "literal será criado em StringPool primeiro, em seguida, através de string ARG constructor String objeto será criado I. e" foo " no heap devido à criação de objeto através de novo operador, em seguida, s3 irá encaminhá-lo.
String s4=new String("foo");
O mesmo que s3
Então ...System.out.println(s1==s2);// **true** due to literal comparison.
E System.out.println(s3==s4);// **false** due to object
A comparação (s3 e s4 são criados em diferentes locais de heap)
String
s são especiais em Java - são imutáveis, e constantes de string são automaticamente transformadas em objetos String
.
Nem se pode estender {[[[0]}, porque é declarado como final
, o que significa que não é permitida nenhuma sub-classe.
As cordas são imutáveis (você nunca pode mudá-las)
String x = "x";
x = "Y";
- a primeira linha irá criar uma variável x que irá conter o valor de texto "x". O JVM vai olhar em seu conjunto de valores de cadeia e ver se " x " existe, se ele existe, ele vai apontar a variável x para ele, se ele não existe, ele vai criá-lo e, em seguida, fazer o atribuição
- a segunda linha irá remover a referência a "x" e ver se "Y" existe no conjunto de valores de cadeia. Se ele existe, ele vai atribuí-lo, se não, ele vai criá-lo primeiro, em seguida, atribuição. Como os valores de string são usados ou não, o espaço de memória no conjunto de valores de string será recuperado.
Comparações de cadeias de caracteres dependem do que está a comparar
String a1 = new String("A");
String a2 = new String("A");
-
a1
não é igual aa2
-
a1
ea2
são referências de objectos - Quando a cadeia é explicitamente declarada, novas instâncias são criadas e as suas referências não serão as mesmas.
I. e.
TextUtility.compare(string 1, string 2)
TextUtility.compareIgnoreCase(string 1, string 2)
TextUtility.camelHump(string 1)
Já que estás a fazer a aula, podes fazer as comparações. o que você quer - compare os valores do texto.
Você não Pode. as coisas entre aspas em Java são especialmente reconhecidas pelo compilador como Strings, e infelizmente você não pode sobrepor isso (ou extender {[[0]} - é declarado final
).
A melhor maneira de responder à tua pergunta seria familiarizar-te com a "String constant pool". Em java, objetos string são imutáveis (que eu.e seus valores não podem ser alterados, uma vez que eles são inicializados), então, quando a edição de um objeto de cadeia de caracteres que você acabar criando uma nova editado objeto de cadeia de caracteres wherease o objeto antigo simplesmente flutua em torno de uma memória especial ares chamada "constante de seqüência de caracteres de piscina". criar um novo objecto de texto por
String s = "Hello";
Só irá criar um objecto de cadeia de caracteres na piscina e na as referências s referir-se-ão a ele, mas usando
String s = new String("Hello");
Você cria dois objetos de cadeia: um na piscina e o outro na pilha. a referência se referirá ao objeto no heap.
Já foi dito o suficiente desde o primeiro ponto. "Polonês" é um texto literal e não pode ser atribuído à classe Caseinsentivivivivestring. Agora sobre o ... segundo ponto- Como faço para que o Caseinsensibilitivestring se comporte como String para que a declaração acima esteja ok (com e w/out string estendendo)? O que é que tem o String que faz com que seja bom apenas ser capaz de passá-lo um literal como esse? Pelo que sei, não há nenhum conceito de" construtor de cópias " em Java, certo?
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 são verdadeiras:
// Lets test the insensitiveness
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;
// 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();
}
/ / testar a classe usando a palavra-chave "Asser"
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>
Isto é, criar um conjunto interno de objectos de Resistência Caseinsensibilizante, e devolver a instância correntemente de lá.
Desta forma, o " = " operador devolve verdadeiro para dois objectos referências que representam o mesmo valor .
Isto é útil quando objectos semelhantes são usados com muita frequência e a criação de custos é dispendiosa.
A documentação da classe de texto indica que a classe usa um conjunto interno
A classe não está completa, algumas questões interessantes surgem quando tentamos caminhar o conteúdo do objeto na implementação da interface CharSequence, mas este código é bom o suficiente para mostrar como esse item no livro poderia ser aplicado.
É importante notar que ao usar o objeto internalPool, as referências não são liberadas e, portanto, não são coletáveis lixo, e isso pode se tornar um problema se um monte de objetos são criados.
Ele funciona para a classe de cadeia porque é usado intensivamente e o conjunto é constituído apenas de objeto "internado".
Ele funciona bem para a classe booleana também, porque há apenas dois valores possíveis.
E finalmente essa é também a razão pela qual valor de (int) in class Integer is limited to -128 to 127 int values.Em seu primeiro exemplo, você está criando uma String, "silly" e, em seguida, passando-a como um parâmetro para o construtor de cópia de outra String, que faz uma segunda String que é idêntica à primeira. Uma vez que as Strings Java são imutáveis (algo que frequentemente fere pessoas que são usadas para strings C), Este é um desperdício desnecessário de recursos. Em vez disso, você deve usar o segundo exemplo, porque ele salta vários passos desnecessários.
No entanto, o texto literal não é um Caseinsensibilitivestring assim lá você não pode fazer o que você quer em seu último exemplo. Além disso, não há nenhuma maneira de sobrecarregar um operador de fundição como você pode em C++ para que não haja literalmente nenhuma maneira de fazer o que você quer. Em vez disso, você deve passá-lo como um parâmetro para o construtor da sua classe. Claro, provavelmente usaria fio.para usar a língua e acabar com isto.
Além disso, o seu tratamento Caseinsensibilizante deve implementar a interface de CharSequence, bem como, provavelmente, a serializável e Interfaces comparáveis. Claro, se você implementar comparável, você deve sobrepor igual() e hashCode() também.CaseInsensitiveString
não é um String
embora contenha um String
. A String
literalmente, por exemplo, "exemplo" só pode ser atribuído a String
.
Caseinsensibilitivestring E String são objectos diferentes. Não podes fazer isso.
CaseInsensitiveString cis = "Polish";
Porque "polaco" é uma cadeia, não um Caseinsensibilitivestring. Se a String estendesse a String CaseInsensitiveString então você estaria bem, mas obviamente não.
E não te preocupes com a construção aqui, não vais fazer objectos desnecessários. Se você olhar para o código do construtor, tudo o que ele está fazendo é armazenar uma referência à cadeia que você passou. Nada mais está a ser criado.No caso String s = nova String ("foobar") está a fazer algo diferente. Você está primeiro criando a string literal "foobar", em seguida, criando uma cópia dela, construindo uma nova string a partir dela. Não há necessidade de criar essa cópia.
String s = "Silly";
Em vez de
String s = new String("Silly");
Eles significam isso ao criar um objeto de cadeia de caracteres porque ambas as afirmações acima criam um objeto de cadeia de caracteres, mas a nova versão String () cria dois objetos de cadeia de caracteres: um em heap e o outro em string constant pool. Portanto, usando mais memória.
Mas quando escreves
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
Você não está criando uma String em vez disso você está criando um objeto de classe CaseInsensitiveString. Por isso você precisa usar o novo operador.
Se eu entendi corretamente, sua pergunta significa por que não podemos criar um objeto atribuindo-lhe diretamente um valor, não vamos restringi-lo a uma embalagem da classe String em java.
Para responder que eu diria apenas, linguagens de programação puramente orientadas a objetos têm algumas construções e diz, que todos os literais quando escritos sozinhos podem ser diretamente transformados em um objeto do tipo dado.
Isso significa que, se o intérprete vir 3, será convertido em um objeto inteiro porque inteiro é o tipo definido para tais literais.Se o interpretador vir alguma coisa entre aspas simples como' a ' irá criar directamente um objecto de carácter tipo, não precisa de O especificar, dado que a linguagem define o objecto por omissão de carácter tipo para ele.
Similarmente, se o interpretador vê algo em"", ele será considerado como um objeto de seu tipo padrão, ou seja, cadeia de caracteres. Isto é um código nativo a trabalhar ao fundo.
Graças a Curso de aula de vídeo do MIT às 6: 00, onde recebi a dica para esta resposta.Em Java a sintaxe "texto" cria uma instância da classe java.idioma.Cadeia. A missão:
String foo = "text";
É uma tarefa simples, sem necessidade de construtor de cópias.
MyString bar = "text";
O que quer que faças, é ilegal, porque a classe MyString não é java.idioma.String ou uma superclasse de java.idioma.Cadeia.
Primeiro, você não pode fazer uma classe que se estende de String, porque String é uma classe final. E o java gerencia Cadeias de caracteres de forma diferente das outras classes, por isso só com String você pode fazer
String s = "Polish";
Mas, para a tua turma, tens de invocar o construtor. Então, esse código é bom.
Eu acrescentaria que Java tem Copy constructors ...
É um construtor comum com um objecto do mesmo tipo que o argumento.Na maioria das versões do JDK as duas versões serão as mesmas:
String s = new String ("silly");
String s = "no longer silly";
Porque as cadeias de caracteres são imutáveis, o compilador mantém uma lista de constantes de cadeias de caracteres e se tentar fazer uma nova irá primeiro verificar se a cadeia de caracteres já está definida. Se for então uma referência à cadeia imutável existente é retornada.
Para esclarecer-quando dizes "String s =" estás a definir uma nova variável que ocupa espaço na pilha - então se você diz "não mais bobo" ou nova String("bobo") exatamente a mesma coisa acontece - uma nova string constante é compilada em sua aplicação e os pontos de referência para isso.
Não vejo a distinção aqui. No entanto, para a sua própria classe, que não é imutável, este comportamento é irrelevante e você deve chamar o seu construtor.Atualização: eu estava errado! Com base num voto negativo e num comentário anexado, testei este facto e apercebi-me de que a minha compreender é errado-nova String ("Silly") realmente cria uma nova string ao invés de reutilizar a existente. Não sei por que isso seria (Qual é o benefício?) mas o código fala mais alto que as palavras!
O texto é uma das classes especiais nas quais você pode criá-las sem a nova parte do anel
É o mesmo queInt x = y;
Ou
Char c;
É uma lei básica que Strings em java são imutáveis e sensíveis a maiúsculas.
String str1 = "foo";
String str2 = "foo";
Ambos str1 e str2 pertencem ao mesmo objeto de String, "foo", B'coz Java gerencia Strings em StringPool, então se uma nova variável se refere à mesma String, ela não cria outra, mas atribui a mesma alerady presente em StringPool.
String str1 = new String("foo");
String str2 = new String("foo");
Aqui tanto o str1 como o str2 pertencem a diferentes objectos, o b'coz new String() cria forçosamente um novo objecto de texto.
O Java cria um objecto de texto para cada texto literal que usa no seu código. Sempre que ""
é usado, é o mesmo que chamar new String()
.
6, 6.0, 'c',
etc. Assim, o texto "literal" "text"
devolve um novo objecto de texto com valor char[] value = {'t','e','x','t}
. Portanto, chamando
new String("text");
É na verdade semelhante a chamar
new String(new String(new char[]{'t','e','x','t'}));
Com sorte, de aqui, você pode ver por que seu livro considera isso redundante.
Para referência, aqui está a implementação do texto: http://www.docjar.com/html/api/java/lang/String.java.html
É uma leitura divertida e pode inspirar algum discernimento. Também é ótimo para iniciantes para ler e tentar entender, como o código demonstra código muito profissional e compatível com a Convenção.Outra boa referência é o tutorial Java sobre Strings: http://docs.oracle.com/javase/tutorial/java/data/strings.html