Desafiadores de Java # 2: comparação de cadeias

Desafiadores de Java # 2: comparação de cadeias


Como sempre, nos atrasamos muito no início do curso, então, ontem, tivemos uma segunda lição entre o novo segmento "Java Developer" . Mas é assim, pequenas coisas na vida, mas por enquanto continuamos a publicar uma série de artigos sobre o Java Challengers, cuja tradução foi preparada para você.


Em Java, a classe String encapsula uma matriz de char ( nota do tradutor - com o java 9 já é uma matriz de byte , consulte Compactar cadeias de caracteres no Java 9 ). Em termos simples, String é uma matriz de caracteres usada para compor palavras, frases ou outras construções.


Encapsulamento é um dos conceitos mais poderosos da programação orientada a objetos. Graças ao encapsulamento, você não precisa saber como a classe String funciona. Você só precisa conhecer os métodos de sua interface.



Quando você olha para a classe String em Java, pode ver como o array char está encapsulado:


 public String(char value[]) { this(value, 0, value.length, null); } 

Para entender melhor o encapsulamento, imagine um objeto físico: uma máquina. Você precisa saber como um carro funciona sob o capô para dirigi-lo? Claro que não, mas você deve saber o que as interfaces do carro fazem: o pedal do acelerador, os freios e o volante. Cada uma dessas interfaces suporta certas ações: aceleração, frenagem, virar à esquerda, virar à direita. O mesmo se aplica à programação orientada a objetos.


O primeiro artigo da série Java Challengers foi sobre sobrecarga de método, amplamente usada na classe String . Sobrecarregar pode tornar suas aulas realmente flexíveis:


 public String(String original) {} public String(char value[], int offset, int count) {} public String(int[] codePoints, int offset, int count) {} public String(byte bytes[], int offset, int length, String charsetName) {} //    ... 

Em vez de tentar entender como a classe String funciona, este artigo o ajudará a entender o que faz e como usá-lo em seu código.


O que é um pool de strings?


A classe String é sem dúvida a classe mais usada em Java. Se criarmos um novo objeto na memória dinâmica (pilha de memória) toda vez que usarmos o String , perderemos muita memória. O pool String resolve esse problema armazenando apenas um objeto para cada valor de linha.


cadeia de caracteres na cadeia de caracteres


Conjunto de linhas em uma linha


Embora tenhamos criado várias variáveis String com os valores Duke e Juggy , apenas dois objetos são criados e armazenados na memória dinâmica (heap). Veja o seguinte exemplo de código para prova. (Lembre-se de que em Java, o operador " == " é usado para comparar dois objetos e determinar se o mesmo objeto é o mesmo ou não.)


 String juggy = "Juggy"; String anotherJuggy = "Juggy"; System.out.println(juggy == anotherJuggy); 

Esse código retornará true porque as duas variáveis String apontam para o mesmo objeto no pool de strings. Seus significados são os mesmos.


A exceção é o new operador.


Agora observe este código - ele se parece com o exemplo anterior, mas há uma diferença.


 String duke = new String("duke"); String anotherDuke = new String("duke"); System.out.println(duke == anotherDuke); 

Com base no exemplo anterior, você pode pensar que esse código retornará true , mas não é. Adicionar um new operador cria um novo objeto String na memória. Assim, a JVM criará dois objetos diferentes.


Métodos nativos

Métodos nativos em Java são métodos que serão compilados usando a linguagem C, geralmente com o objetivo de gerenciar memória e otimizar o desempenho.

Conjuntos de strings e método intern()


Para armazenar seqüências de caracteres em um pool, é usado um método chamado String interning.


Aqui está o que o Javadoc nos diz sobre o método intern() :


  /** *      . * *   ( )   {@code String}. * *    intern,     , *    {@code String},   *  {@link #equals(Object)},     . * ,   {@code String}   *        {@code String}. * *   ,      {@code s}  {@code t}, * {@code s.intern() == t.intern()}  {@code true} *    ,  {@code s.equals(t)}  {@code true}. * *       . *      3.10.5 The Java™ Language Specification. * * @returns ,         , * , ,       . * * @jls 3.10.5 String Literals */ public native String intern(); 

O método intern() é usado para armazenar cadeias de caracteres em um conjunto de cadeias. Primeiro, ele verifica se uma linha já criada existe no pool. Caso contrário, ele cria uma nova linha no pool. A lógica do conjunto de linhas é baseada no padrão Flyweight .


Agora, observe o que acontece quando usamos new para criar duas linhas:


 String duke = new String("duke"); String duke2 = new String("duke"); System.out.println(duke == duke2); //    false System.out.println(duke.intern() == duke2.intern()); //    true 

Diferente do exemplo anterior com a new palavra-chave, neste caso, a comparação retornará true . Isso ocorre porque o uso do método intern() garante que a string esteja no pool.


Método equals na classe String


O método equals() é usado para verificar se duas classes são iguais ou não. Como equals() está localizado na classe Object , cada classe Java a herda. Mas o método equals() deve ser substituído para que funcione corretamente. Obviamente, as substituições de String equals() .


Dê uma olhada:


 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (coder() == aString.coder()) { return isLatin1() ? StringLatin1.equals(value, aString.value) : StringUTF16.equals(value, aString.value); } } return false; } 

Como você pode ver, o valor da classe String é comparado através de equals() , e não através de uma referência a objeto. Não importa se as referências aos objetos são diferentes; condições serão comparadas.


Métodos comuns de String


Há mais uma coisa que você precisa saber antes de resolver o problema de comparação de cadeias.


Considere os métodos mais comuns da classe String :


 //         trim() //     substring(int beginIndex, int endIndex) //    length() //  ,     replaceAll(String regex, String replacement) // ,     CharSequence   contains(CharSequences) 

Resolver o problema de comparação de cadeias


Vamos verificar o que você aprendeu sobre a classe String resolvendo um pequeno quebra-cabeça.


Nesta tarefa, você compara várias linhas usando os conceitos que aprendeu. Observando o código abaixo, você pode determinar o valor de cada result variável?


 public class ComparisonStringChallenge { public static void main(String... doYourBest) { String result = ""; result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; result += "flexibleCode" == "flexibleCode" ? "2" : "3"; result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; System.out.println(result); } } 

Qual será a conclusão?


  • A: 02468
  • B: 12469
  • C: 12579
  • D: 12568

A resposta correta é dada no final do artigo.


O que aconteceu agora? Noções String comportamento das String


Na primeira linha, vemos:


 result += " powerfulCode ".trim() == "powerfulCode" ? "0" : "1"; 

Nesse caso, o resultado é false , porque quando o método trim() remove espaços, ele cria uma nova String usando o new operador.


A seguir, vemos:


 result += "flexibleCode" == "flexibleCode" ? "2" : "3"; 

Não há segredo aqui; as linhas são as mesmas no pool de linhas. Essa comparação retorna true .


Então, temos:


 result += new String("doYourBest") == new String("doYourBest") ? "4" : "5"; 

O uso de new leads para a criação de duas novas linhas e não importa se seus valores são iguais ou não. Nesse caso, a comparação será false mesmo que os valores sejam os mesmos.


Seguinte:


 result += new String("noBugsProject") .equals("noBugsProject") ? "6" : "7"; 

Como usamos o método equals() , o valor da string será comparado, não a instância do objeto.


Nesse caso, não importa se objetos diferentes ou não, pois o valor é comparado. O resultado é true .


Finalmente, temos:


 result += new String("breakYourLimits").intern() == new String("breakYourLimits").intern() ? "8" : "9"; 

Como você viu anteriormente, o método intern() coloca uma string em um pool de strings. Ambas as linhas apontam para o mesmo objeto, portanto, neste caso, true .


Erros comuns de string


Pode ser difícil determinar se duas linhas apontam para o mesmo objeto ou não, especialmente quando as linhas contêm o mesmo valor. É útil lembrar que o uso de new sempre leva à criação de um novo objeto na memória, mesmo que os valores da string sejam os mesmos.


O uso de métodos String para comparar referências de objetos também pode ser complicado. A peculiaridade é que, se o método mudar algo na linha, haverá referências diferentes aos objetos.


Alguns exemplos para ajudar a esclarecer:


 System.out.println("duke".trim() == "duke".trim()); 

Essa comparação será verdadeira porque o método trim() não cria uma nova linha.


 System.out.println(" duke".trim() == "duke".trim()); 

Nesse caso, o primeiro método trim() gera uma nova linha, pois o método fará seu trabalho e, portanto, os links serão diferentes.


Finalmente, quando trim() faz seu trabalho, ele cria uma nova linha:


 //   trim   String new String(Arrays.copyOfRange(val, index, index + len), LATIN1); 

O que lembrar sobre cordas


  • As linhas não são mutáveis, portanto, o estado da linha não pode ser alterado.


  • Para economizar memória, a JVM armazena cadeias em um conjunto de cadeias. Ao criar uma nova linha, a JVM verifica seu valor e aponta para um objeto existente. Se o conjunto não tiver uma linha com esse valor, a JVM criará uma nova linha.


  • O operador " == " compara referências de objetos. O método equals() compara valores de sequência. A mesma regra se aplicará a todos os objetos.


  • Ao usar o new operador, uma nova linha será criada na pilha (Nota do tradutor - está escrito no original que está na piscina, mas não é assim, graças a zagayevskiy ), mesmo se houver uma linha com o mesmo valor.



A resposta


A resposta para esse problema é D. A conclusão será 12568.


Para continuar ...

Source: https://habr.com/ru/post/pt428449/


All Articles