Uma String, antes de tudo, é um objeto da classe String. Os literais String (guardados na memória como objetos String) são escritos como um conjunto de caracteres entre aspas duplas.

O Java aborda todos os literais String com o mesmo conteúdo de um único objeto String que tem diversas referências a ele. Isso conserva memória.

Para o Java, cada caractere da String é um caractere Unicode de 16 bits.

Como provavelmente você já esteja ciente, a classe String possui muitos construtores, então podemos utilizar um modo mais eficaz para criar novas referências.


        String str = new String(“xyz”);
        

Já que você utilizará Strings constantemente, poderá também fazer da seguinte forma:


        String str = “xyz”;
        

Avalie a lista de vários construtores de String no próximo exemplo.


        public class Construtores {

        /**
        * @param args
        */
        public static void main(String[] args) {
        char charArr[]={'f','e','l','i','z'};
        byte byteArray[]={'a','b','W','&',(byte)'¨'};
        StringBuffer buffer;
        String a,a1,a2,a3,a4,a5,a6,a7,output;
        s=new String("Olá");
        buffer = new StringBuffer("Java Devmedia");
        s1= new String();
        s2=new String(s);
        s3=new String(charArr);
        s4=new String(charArr,2,3);
        s5=new String(byteArr,0,1);
        s6=new String(byteArr);
        s7=new String(buffer);
        output = a1+" "+a2+" "+a3+" "+a4+" "+a5+" "+a6+" "+a7;
        System.out.println(output);
        }
        }
        

O que distingue objetos String dos outros é a inalterabilidade. Uma vez dado um valor a uma String, esse valor jamais poderá ser modificado. Mesmo o objeto String não possa mais ser mudado, sua variável de referência poderá.

A JVM não pode alterar nessa String, sendo assim cria um novo objeto String e dá a ele o novo valor, em caso de adição de caracteres para o mesmo objeto em questão. Imagine quantos novos objetos são criados. Dessa totalidade, existe algum já selecionado para a coleta de lixo? Ou seja, objetos inatingíveis?


        public class StringTeste {
        /**
        * @param args
        */
        public static void main(String[] args) {
        String s = "abcdef";//1 String
        System.out.println(s.hashCode());
        s=s+"fghij";//Outro objeto String
        System.out.println(s.hashCode());
        s=s.concat("klmno");//Outro objeto
        System.out.println(s.hashCode());
        }
        }
        

E se não tivéssemos a sorte ou a visão de fazer uma segunda de referência para a String “abcdef” antes de chamarmos s = s.concat(“ coisas a mais?”)? Nessa situação, a String original não modificada como “abcdef” ainda permaneceria na memória, mas seria considerada perdida.

Concluiremos mostrando o tipo de questionamento capcioso sobre String que podemos nos deparar na prova da certificação. Não se precipite e use um papel para raciocinar. Orientação: tente manter um controle de quantos objetos e variáveis de referência permanecem e quais se referem a quê.


        String x1 = "primavera";
        String x2 = x1+" verão";//s2 é uma nova String que aponta para primavera verão
        x1.concat("outono");//referência criada e perdida, s1 não muda!
        x2.concat(x1);//referência criada e perdida, s2 não muda!
        x1+=" inverno";//referência criada, atribuída a s1, que passa a apontar para a String "primavera inverno"
        System.out.println(x1+" "+x2);
        

Memória e objetos String

Com intuito de deixar Java mais eficiente na utilização da memória, a JVM deixa reservada uma área especial conhecida como “pool constante de Strings”. Quando o compilador localiza uma String literal, examina o pool para ver se já possui uma idêntica.

Avalie o exemplo e a saída. A partir desse trecho de código existe a possibilidade de entendermos como acontece o reaproveitamento de memória.


        package devmedia;
        public class Main {
        /**
        * @param args
        */
        public static void main(String[] args) {
        String y1="EE";
        String y2="EE";
        if(y1==y2){
        System.out.println("primeiro é igual");
        }else{
        System.out.println("primeiro não é igual ");
        }
        String a1 ="EE";
        String a2 = new String("EE");
        if(a1==a2){
        System.out.println("segundo é igual");
        }else{
        System.out.println("segundo não é igual");
        System.out.println(a1.hashCode()+" "+a2.hashCode());
        System.out.println(a1.equals(a2));
        }
        }
        }
        

Saída:
primeiro é igual
Segundo não é igual
2208 2208
true

Apenas reforçando o conceito de que os métodos equals() e hashCode() já vêm sobrepostos diretamente da API da classe String, devemos utilizar equals() no intuito de realizar comparações.

Se muitas variáveis de referência apontam para uma mesma String sem mesmo terem informação disso, não seria bom se alguma delas pudesse ter o valor da String modificado. Isso nada mais é que reaproveitamento de memória.

Observaremos alguns exemplos de como objetos String podem ser criados, partindo do pressuposto que não haja nenhum objeto String presente no pool.


        String str ="123";//cria um objeto String e uma variável de referência
        String str = new String("123");// cria dois objetos e uma variável de referência
        

Nessa situação, já que utilizamos a palavra-chave new, Java criará um novo objeto String na memória comum e não no pool, e str o referenciará. Ainda mais, a String literal “123” será adicionada no pool.

Principais métodos da classe String

Os métodos abaixo são alguns dos mais utilizados da classe String, além de serem os que possivelmente estarão no exame.

  • charAt() -> retorna o caractere situado no índice específico
  • concat() -> anexa uma String no fim de outra, produzindo uma nova String
  • equalsIgnoreCase() -> define a igualdade de duas Strings, ignorando a caixa
  • length() -> retorna a quantidade de caracteres

Atenção! Os arrays possuem um atributo length. Você pode encontrar perguntas no exame que tentem utilizar o atributo length em um objeto String ou o método length() em um array. Todas as situações originarão erros de compilação.

  • replace() -> substitui ocorrências de um caractere por outro caractere
  • subString() -> retorna parcialmente uma String
  • toLowerCase() -> retorna uma String apenas com minúsculas
  • toUpperCase() -> retorna uma string apenas com maiúsculas
  • toString() -> retorna o valor de uma String
  • trim() -> remove os espaços em branco no início e no final de Strings

Na sequência continuaremos falando de StringBuilder e StringBuffer. E já faremos uma introdução sobre a classe File.


Leia todos artigos da série