Quando discutimos arranjos vimos que eles são objetos especiais. Os arranjos possuem "inicializadores" e arranjos podem ser indexados. As cadeias de caracteres são objetos especiais também, mas em um sentido diferente. Uma cadeia de caractere é o único objeto que possui uma representação no código fonte do programa, ou seja uma cadeia de caractere é o único objeto que tem um literal.
Considere o seguinte trecho de programa:
System.out.println(123);
System.out.println(3.1415);
System.out.println("Ola!");
O tipo do literal 123 é int. o tipo do literal 3.1415
é
double. Em Java int e double são tipos
primitivos. O tipo da cadeia de caracteres "Ola!" é String.
Em Java String é uma classe(class). Uma classe
é o elemento da Linguagem Java que define o estado e o comportamento
de seus objetos. Mais a frente no curso iremos ver as classes com mais
detalhes. Neste ponto do curso iremos apenas estudar uma classe especial
denominada String cujos objetos contêm cadeias de caracteres.
Uma variável do tipo String é uma variável
do tipo referência, ou seja, contém um endereço de
objeto. Uma variável do tipo String pode ser iniciada ou
inicializada de forma semelhante a uma variável de tipo primitivo.
A iniciação é feita com literais do tipo String
. Um literal do tipo String é uma seqüência de caracteres
iniciada e terminada com aspas. Podemos utilizar o operador de concatenação
de cadeias (+). O operador de concatenação permite representar
uma cadeia em diferentes linhas do texto do programa. Exemplo de declaração
de variáveis do tipo cadeia de caracteres já inicializadas:
String s1="Universidade ";
String s2="Federal de";
String s3=" Minas "+
"Gerais";
String universidade=s1+s2+s3;
No trecho de programa acima a variável universidade
é inicializada utilizando o operador de concatenação
de cadeias de caracteres. Os literais de tipo String podem ser usados em
comandos de atribuição:
String universidade;
universidade="Universidade Federal de Minas
Gerais";
No trecho acima a variável universidade recebe o endereço
de memória onde fica um objeto contendo a cadeia de caracteres "Universidade
Federal de Minas Gerais". A figura abaixo mostra uma representação
gráfica simplificada para o que discutimos acima:
O conteúdo da variável universidade é um endereço de um bloco de memória. Este bloco de memória é o objeto que contém a cadeia de caracteres. A distinção entre a cadeia de caracteres e o objeto não é muito reforçada em alguns textos. Um objeto é também referido como uma instância, o objeto acima é uma instância da classe String. Não são mostrados todos os campos do objeto, apenas um campo (que não fica disponível para o programador!) e que contém uma referência para a classe String. A classe String não é detalhada, mas uma classe pode definir campos e métodos (methods).
Um método corresponde a um código que implementa alguma funcionalidade relacionada à classe ou a um objeto. Os métodos que implementam uma funcionalidade relacionada à classe são denominados métodos estáticos (static) ou métodos de classe e os métodos que implementam uma funcionalidade relacionada ao objeto são denominados não-estáticos ou métodos de instância. Uma chamada ou invocação de método corresponde a um comando que altera o fluxo de controle. Uma chamada ou invocação de método desvia o fluxo de controle para o código de máquina do método, um mecanismo, denominado mecanismo de retorno, permite, terminada a execução do método, que o controle retorne ao comando seguinte à chamada. Os métodos estáticos são invocados utilizando o nome da classe seguido do operador '.' seguido do nome do método. Os métodos não-estáticos são invocados utilizando uma referência para o objeto seguido do operador '.', seguido do nome do método. Abaixo são mostrados alguns dos métodos da classe String:
O trecho de programa abaixo imprime o comprimento, em termos de números
de caracteres, de uma cadeia de caracteres referenciada pela variável
cordao:
String cordao="abcdefg";
System.out.println(cordao.length());
No trecho acima o método não-estático length()
da classe String é
invocado. Invocar um método consiste
em desviar o fluxo de controle para o código correspondente a este
método, mas antes que ocorra o desvio, de alguma forma, é
salvo o ponto no qual o fluxo de controle deverá retornar. O println()
também é um método. A ordem de invocação
é a seguinte: o compilador primeiramente gera código para
invocar o método length(), após a invocação
de length() é gerado o código para invocar println().
A execução do código correspondente a length( determina o número de caracteres e retorna este valor. O valor retornado por um método tem que ter um tipo. O método length() da classe String é um método do tipo int, ou seja retorna valores inteiros. Mais a frente na disciplina iremos ver como definir classes e em particular como definir métodos. Observe que os objetos correspondentes a arranjos têm um campo length enquanto que objetos correspondentes a cadeias de caracteres compartilham o método length() da classe String. A execução de um método pode receber valores através de parâmetros ou argumentos. Os parâmetros são sempre de um determinado tipo. O método length() não tem parâmetros. O parâmetro do método println() deve ser do tipo String, que será discutido mais a frente na disciplina. O valor retornado pelo método length() é do tipo int, o compilador cuida para que seja feita a conversão d o valor de tipo int para tipo String.
O trecho de programa abaixo utiliza o método charAt().
Este método possui um parâmetro do tipo int e
retorna um valor do tipo char:
String cordao="abcdefg";
for(int i=0; i<cordao.length(); i++) System.out.print(cordao.charAt(i));
System.out.println();
O trecho acima tem efeito semelhante ao seguinte trecho:
String cordao="abcdefg";
System.out.println(cordao);
O método charAt() recebe como parâmetro um valor inteiro que deve estar entre 0 e length()-1. Se o valor do parâmetro não atender a estes limites haverá um erro em tempo de execução. O método devolve o (valor do parâmetro+1)-ésimo caractere da cadeia de caracteres. Se o argumento de charAt() for menor que 0 ou maior ou igual ao comprimento da cadeia ocorre um erro de execução: IndexOutOfBoundsException.
Um objeto, diretamente ou através de sua classe, é
constituido de campos(fields), métodos(methods) e
constructores( constructors). Os campos e métodos já
foram parcialmente discutidos: os campos correspondem a posições
de memória e os métodos são códigos que recebem
0 ou mais valores e devolvem 0 ou 1 valor. O trecho de programa abaixo
ilustra como que podemos utilizar um arranjo de caracteres para construir
uma cadeia de caracteres correspondente à seqüência do
arranjo:
char[] arranjoCar;
arranjoCar= new char[]{'a', 'b', 'c ', 'd
', 'e ', 'f '};
String cordao;
cordao= new String(arranjoCar);
No trecho acima é utilizado o operador new no contexto
de arranjos e no contexto de classes. A expressão new char[]
aloca um bloco de memória contendo um arranjo do tipo char
inicializado conforme especificado acima. A expressão new String
irá alocar um objeto do tipo String e retornar o endereço
do bloco de memória onde foi alocado este objeto. A expressão
String(arranjoCar)
junto ao operador new corresponde a um construtor (constructor).
Um construtor instrui o operador
new em como deve ser construído
o novo objeto. A classe String tem vários construtores. Os
contrutores têm o mesmo nome da classe e só diferem entre
si pelo número e tipo de parâmetros. Um construtor com apenas
um parâmetro do tipo arranjo de caractere aloca um objeto do tipo
String onde a cadeia de caractere é formada pela concatenação
dos caracteres do arranjo correspondente.
Podemos utilizar Strings para formar arranjos:
String[] meses={"", "Janeiro", "Fevereiro",
"Março",...,"Dezembro"};
No arranjo acima foi incluído, na posição de índice
0, um string de comprimento zero. Uma outra solução seria
o uso de null. Abaixo exemplificamos a utilização
de um método estático da classe String. Considere
que temos uma variável do tipo int contendo o dia do mês
e uma variável também do tipo int contendo o número
do mês.. No trecho abaixo é construido um string do dia do
mês utilizando o método estático valueOf()
da classe String:
int numDoDia=...;
int numDoMes=...;
String data="dia " + String.valueOf(numDoDia)+
" de " + meses[numDoMes];
No trecho acima invocamos o método valueOf()
da classe String. Este método cria um objeto contendo uma
cadeia de caracteres correspondente à conversão do valor
inteiro do parâmetro numDoDia e retorna a referência para este
objeto. Descrito de outra maneira: valueOf() retorna a representação
em cadeia de caracteres do argumento numDoDia.
Uma chamada de método que retorne uma referência pode ser
qualificada, utilizando o operador '.', com nova chamada de método.
Considere o trecho de programa abaixo:
String universidade= "Universidade Federal
de Minas Gerais";
String s=universidade.substring(0,19);
O método substring() retorna uma referência para
um objeto contendo a subcadeia "Universidade Federal". O primeiro parâmetro
é o índice de início e o segundo parâmetro é
o índice final da subcadeia que é copiada da instância.
Como o método substring() devolve uma referência
para uma instância de String, podemos invocar qualquer método
de instância utilizando esta referência:
String universidade= "Universidade Federal
de Minas Gerais";
String x=universidade.substring(24,35).substring(0,4);
O trecho acima mostra duas chamadas do método substring(). A primeira chamada retorna a cadeia "Minas Gerais" e a segunda chamada retorna a cadeia "Minas".
Para comparar cadeias existem os métodos: equals(), equalsIgnorecase(),
compareTo() e compareToIgnoreCase(). Se for utilizada o operador == da
Linguagem Java com variáveis do tipo String a comparação
será feita com as referências:
String ab="ab";
String bc="bc";
String s1=ab+"c";
String s2="a"+bc;
if(s1==s2) System.out.println("valores de
s1 e s2 iguais!");
No trecho acima o conteúdo de s1 e s2 são duas referências
diferentes (foi preciso alguma prestidigitação - sem trocadilhos
- porque o compilador tenta reutilizar cadeias iguais!). Se quisermos comparar
o conteúdo das intâncias devemos utilizar os métodos
mencionados:
String ab="ab";
String bc="bc";
String s1=ab+"c";
String s2="a"+bc;
if(s1==s2) System.out.println("Endereço
em s1 igual ao endereço em s2!");
if(s1.equals(s2)) System.out.println("Instancias
com cadeias iguais!")
O método compareTo() é um método de instância
que tem um argumento do tipo String e retorna um valor do tipo int.
O valor retornado é menor que zero quando a cadeia do argumento
é lexicograficamente maior que a cadeia da instância, zero
quando a cadeia do argumento é a mesma da instância e maior
que zero quando a cadeia do argumento é menor que a cadeia da instância:
String abc="abc";
String bcd="bcd";
if(abc.compareTo(bcd)==0)
System.out.println("cadeias iguais:"+abc);
if(abc.compareTo(bcd)<0)
System.out.println(abc+ " precede
lexicograficamente "+ bcd);
if(abc.compareTo(bcd)>0)
System.out.println(bcd+ "precede lexicograficamente
"+abc);
Os métodos equalsIgnoreCase() e compareToIgnoreCase() são similares à descrição acima mas ignoram se as letras são maiúsculas ou minusculas.
O método toLowerCase() retorna uma instância de
String na qual todos os caracteres foram convertidos para minúsculas.
O método toUpperCase() retorna uma instância de String
na qual todos os caracteres foram convertidos para letras maiúsculas:
String universidade= "Universidade Federal
de Minas Gerais";
String uniMinusculas=universidade.toLowerCase();
String unimaiusculas=universidade.toUpperCase();
A linguagem Java tem a classe Character que possui vários métodos estáticos úteis no tratamento de caracteres individuais. Os seguintes métodos recebem um caractere como argumento e devolvem um valor booleano: isDigit(), isLetter(), isLetterOrDigit(), isLowerCase(), isSpaceChar(), isUpperCase().
Exercícios