Informações
| Tipo: | Tutorial |
|---|---|
| Data de Publicação: | 01/01/2004 |
| Revisado em: | 01/01/2004 |
Vote!
Tags Relacionadas
Comentários ( 0 )
Imprimir
Operadores e Atribuição
por:
Teresa Raquel (teresa_raquel@yahoo.com)
Este capítulo descreve o conjunto de operadores existentes na linguagem Java. A maioria deles foi herdada da linguagem C++, com alguns diferentes aspectos de comportamento, detalhados nas próximas seções.
Introdução
Este capítulo descreve o conjunto de operadores existentes na linguagem Java.
A maioria deles foi herdada da linguagem C++, com alguns diferentes
aspectos de comportamento, detalhados nas próximas seções. Na tabela 1,
tais operadores estão listados por ordem decrescente de precedência
Dúvidas podem ser tiradas pelo endereço
teresa_raquel@yahoo.com.br
| Categoria | Operadores
| Unário | ++ - - + - ! ~ ()
| Aritmético | * / % | + - Deslocamento | << >> >>>
| Comparação | < <= > >= instanceof | == != Bit-a-bit | & ^ |
| Lógico de Curto-circuito | && ||
| Condicional | ?:
| Atribuição | = "op="
| |
Antes de descrever cada um dos operadores listados na tabela 1 é importante dissertar a respeito da ordem de avaliação dos operandos em uma expressão. Geralmente, o resultado de uma sentença será calculado como se os operandos tivessem sido analisados da esquerda para a direita. No caso de declarações, a associatividade é à direita, ou seja, à expressão mais à direita é a expressão avaliada primeiro. Considere o trecho de código a seguir:
1. int a[] = {3, 4};
2. int b = 1;
3. a[b] = b = 0;
|
Neste exemplo, pode não estar muito claro que elemento do array é modificado: 0 ou 1? Uma verificação da esquerda para a direita faz com que a expressão a[b] seja avaliada em primeiro lugar; logo, o elemento do array selecionado é o elemento de posição 1.
Operadores Unários
Nesta seção serão apresentados os operadores unários existentes na linguagem Java, ou seja, operadores que trabalham com apenas um único operando. São sete os operadores unários:
- os operadores de incremento e decremento: ++ --
- o mais e o menos unário: + -
- o operador de inversão de bit-a-bit: ~
- o não booleano: !
- o cast: ()
Os Operadores de Incremento e Decremento: ++ e --
Os operadores de incremento e decremento modificam o valor de uma variável adicionando 1 ao seu valor ou subtraindo 1 do seu valor, respectivamente. Assim, para uma variável x de valor 5, tanto a expressão ++x como a expressão x++ resultam no valor 6 armazenado na variável x. Analogamente, as expressões --x e x-- resultam no valor 4 armazenado na variável x, quando x inicialmente tem valor 5.
A posição do operador em relação à variável é relevante para se determinar o resultado que a expressão produz, isso quer dizer que a posição do operador afeta o resultado da expressão. Para esclarecer esse fato, deve-se atentar para a diferença existente entre o valor armazenado na variável cujo operador de incremento ou decremento está sendo aplicado e o valor retornado pela expressão na qual os operadores são aplicados. Tanto ++x como x++ armazenado na variável x. A diferença está no fato do valor da expressão ser diferente. Na instrução y = x++, o valor armazenado na variável y é o valor original da variável x, enquanto que na instrução y = ++x. Tal comportamento está ilustrado na tabela 2.
| Valor inicial de x | Expressão | Valor final de y | Valor final de x |
| 5 | y = x++ | 5 | 6 |
| 5 | y = ++x | 6 | 6 |
| 5 | y = x -- | 5 | 4 |
| 5 | y = -- x | 4 | 4 |
Em suma, quando um operador de incremento ou decremento está à esquerda de uma variável, neste caso chamados de pré-incremento e pré-decremento, o valor da variável é modificado antes dele fazer parte do cálculo restante da expressão. Adversamente, quando o operador está posicionado à direita de uma variável no cálculo da expressão é utilizado o valor original da variável, e o incremento ou decremento somente é realizado após a expressão ter sido calculada.
O Mais e o Menos Unário: + e -
O operador + unário não produz nenhum efeito em um dado valor numérico, a não ser enfatizar a sua natureza positiva. O - unário, por sua vez, nega um valor numérico, atribuindo à ele um sinal oposto ao que possuía. Vale ressaltar que tanto o + como o - unário não são aplicados apenas para valores literais ou variáveis; eles podem ser igualmente aplicados a expressões numéricas.
O Operador de Inversão bit-a-bit: ~
A linguagem Java provê uma representação de máquina independente de plataforma para cada um dos seus tipos primitivos. Isso quer dizer que os operadores de manipulação de bits em Java são mais úteis, uma vez que o padrão de bits para representação de um tipo em particular é sempre o mesmo e não retrata dependências de plataforma.
O operador ~, em um valor binário, converte todos os bits com valor 1 para o valor 0 e os bits com valor 0 para o valor 1. Por exemplo, este operador aplicado a um byte contendo o valor 00001111, resulta no valor 11110000.
O Não Booleano: !
O operador ! inverte o valor de uma expressão do tipo boolean. Logo, !true retorna false e !false retorna true. Este operador é muito utilizado na condição de sentenças como if e while.
O Operador Cast: (tipo)
A operação de casting é usada quando se quer converter tipos de dados em uma
expressão. Esse tipo de conversão só é possível quando os tipos de dados são
tipos compatíveis entre si. Tais tipos tanto podem ser tipos primitivos como
podem ser objetos.
O código abaixo representa um casting entre tipos primitivos, no qual um valor
do tipo double é forçado a ser do tipo int.
int area = (int)(Math.PI * 2);
Um valor do tipo double, como no caso do valor Math.PI, não pode ser representado por um valor do tipo int, fazendo com que o compilador rejeite a expressão acima, no caso da ausência do cast (int). Com o cast o compilador entende que de fato era intenção do programador converter o valor double em um valor int, e aceita a instrução.
Abaixo segue um outro exemplo de cast, sendo este agora realizado entre objetos.
Vector vetor = new Vector();
vetor.add("Hello");
String str = (String)vetor.elementAt(0);
|
Neste exemplo, um elemento String foi adicionado ao objeto Vector. Como o método elementAt() retorna um Object, um cast se faz necessário quando se quer recuperar o objeto da estrutura Vector e armazenar o valor retornado em uma String. Embora o compilador aceite esse cast, outras verificações são realizadas em tempo de execução para determinar se o objeto extraído do Vector é realmente uma String.
Operadores Aritméticos
Os operadores aritméticos representam o segundo mais alto nível de precedência de operadores em Java. Este grupo inclui os operadores aritméticos relativos às quatro operações fundamentais da matemática, além do operador módulo, na seguinte precedência:
- mais alta - multiplicação, divisão e módulo: *, / e %
- mais baixa - adição e subtração: + e -
Os Operadores de Multiplicação e Divisão: * e /
Os operadores * e / fazem multiplicação e divisão de todos os tipos numéricos e char. O resultado de uma expressão quando se é usado um desses operadores é calculado usando a representação int ou long para os operandos, ou seja, há a promoção dos tipos dos operandos para int ou long numa expressão com tais operadores. Quando o resultado de uma expressão é grande o suficiente para ultrapassar o valor máximo que pode ser representado, o valor final da expressão pode ser um valor sem sentido. Por exemplo, o tipo byte pode representar números de -128 até +127. Supondo que duas variáveis do tipo byte, com valores 64 e 4, sejam multiplicadas, o resultado da multiplicação deve produzir 256 (além do limite de um byte). Se o resultado for armazenado em uma variável do tipo byte, seu valor será 0, o que não corresponde ao valor real.
O resultado de uma divisão é sempre forçado para o tipo int, fazendo com que a parte fracionária do número resultante seja perdida. Por exemplo, o resultado real da expressão 7/4 é 1.75; porém, em Java a expressão citada anteriormente resulta no valor inteiro 1.
Sejam as expressões abaixo:
1. int a = 12345, b = 234567, c, d; 2. c = a * b / b; 3. d = a / b * b; |
Na expressão 2, a multiplicação causa overflow, uma vez que o resultado ultrapassa
o valor máximo para int. O valor armazenado em c é -5965, um valor que não corresponde
ao resultado real da operação. Na expressão 3, a divisão é realizada primeiro,
retornando o valor 0 e produzindo um resultado catastrófico para toda a expressão: 0.
Um detalhe importante a ser lembrado é que a divisão de um número inteiro por
zero pode gerar uma ArithmeticException.
O Operador Módulo: %
O operador % retorna o resto da divisão entre dois números. Por exemplo, a expressão:
x = 7 % 4
armazena na variável x o valor 3. Embora pareça estranho, o operador "%" pode ser aplicado também para números negativos e de ponto flutuante. Para entender como o % funciona nesses casos é importante esclarecer o comportamento real deste operador. Na realidade o operador módulo funciona da seguinte forma: o valor absoluto do operando da direita é subtraído do valor absoluto do operando da esquerda, e o resultado tem o mesmo sinal do operando da esquerda. Tal ação é executada até o momento em que o valor absoluto do resultado tem o valor menor do que o valor absoluto do operando da direita. A figura 1 mostra alguns exemplos que ilustram o comportamento do operador módulo.
17 % 5 17 - 5 --> 12 12 - 5 --> 7 7 - 5 --> 2 2 < 5, então 17%5 = 2 7.6 % 2.9 7.6 - 2.9 --> 4.7 4.7 - 2.9 --> 1.8 1.8 < 2.9, então 7.6%2.9 = 1.8 -5 % 2 5 - 2 --> 3 3 - 2 --> 1 1 < 2, então -5%2 = -1 -5 % -2 5 - 2 --> 3 3 - 2 --> 1 1 < 2, então -5%2 = -1 |
Os Operadores de Adição e Subtração: + e -
Os operadores + e - realizam adição e subtração de qualquer tipo numérico. Em Java, não é permitida a sobrecarga de operadores, como acontece em outras linguagens de programação, como C. Quando os operadores + e - são utilizados para realizar a adição e a subtração de valores numéricos, seu significado é simples e familiar. Algumas promoções podem ocorrer durante a operação e o resultado pode produzir overflow. Quando as operações de + e - causam overflow ou underflow o resultado pode não fazer sentido, mas nenhuma exceção ocorre.
Além da operação de adição de valores numéricos, o operador + pode ter como operando um objeto String. O resultado da operação é a concatenação dos operandos em único objeto String.
Para uma expressão com o operador + e dois operandos de tipos numéricos primitivos, o resultado:
- é de um tipo numérico primitivo;
- é no mínimo int, devido ao fato das promoções no momento da realização da operação;
- é, no mínimo, de um tipo tão largo quanto o do mais largo operando;
- pode do tipo do resultado, quando todos os operandos são promovidos para este tipo no cálculo da expressão. O resultado pode produzir overflow ou perda de precisão.
O operador + na concatenação de Strings
Quando um dos operandos de uma expressão com o operador + são objetos String, o operador trabalha como operador de concatenação de texto e os operandos são manipulados como cadeias de caracteres. Se todos os operandos forem de fato String, a operação é simples. Porém, se um dos operandos não for um objeto String ele é então convertido para String antes da concatenação ser executada. A conversão de um objeto para uma String é feita simplesmente chamando o método toString() definido na classe Object. Tal método produz uma String que contém o nome da classe do objeto e um identificador do objeto, separado pelo símbolo @. Por exemplo, o valor java.lang.Object@lcc6dd é um valor retornado pela chamada de toString() em um objeto Object. Geralmente, as subclasses de Object sobrepõem o método toString() para retornar um valor mais significativo.
Tipos primitivos são convertidos para String chamando-se métodos utilitários existentes nas classes wrapper. Por exemplo, a conversão de um valor int para String é realizada através do método estático Integer.toString().
Portanto, para uma expressão com o operador + na qual um dos operandos não é um tipo numérico primitivo:
- um dos operandos, no mínimo, deve ser uma String. Do contrário, a expressão está incorreta;
- os operandos que não são String são convertidos para String através da chamada do método toString().
Alguns Erros Aritméticos
1. A divisão de um número inteiro por zero, incluindo o operador %, lança ArithmeticException.
2. Nenhuma outra operação causa uma exceção. O resultado é calculado e a operação retorna o seu valor, mesmo quando este valor está incorreto em termos de aritmética.
3. Cálculos de ponto flutuante que produzem valores fora da faixa de abrangência de float ou de double são representados como infinito, menos infinito ou NaN (do inglês Not a Number). As classes Float e Double possuem constantes para representação desses valores. O valor NaN representa um valor não aritmético, como, por exemplo, a raiz quadrada de um número negativo, e qualquer expressão que compare um valor numérico com o valor NaN retorna false. A forma mais apropriada de se verificar se uma dada variável é um NaN é através do método estático isNan()existente nas classes Float e Double. Logo, sendo x uma variável que contém o valor NaN, todas as seguintes expressões retornam false:
x < Float.NaN x < Float.Nan x == Float.Nan |
E a declaração que retorna true é:
Float.isNaN(x);
4. Cálculos utilizando inteiros, exceto divisão por zero, que causam overflow ou outro erro podem produzir uma representação em bits com o sinal errado. Esse erro é refletido no resultado da operação.
Operadores de Deslocamento: <<, >> e >>>
Operação de deslocamento corresponde simplesmente a mover bits para a direita ou para a esquerda. Exemplos de deslocamento estão retratados na figura 2.| Dado original | 00000000 | 11000000 |
| Deslocado 1 bit para a esquerda | 00000000 | 10000000 |
| Deslocado 1 bit para a direita | 00000000 | 01100000 |
O resultado de um valor que sofreu deslocamento contém a mesma quantidade de bits do valor original. Os bits deslocados para fora da representação são descartados. Os novos bits que entram na representação após o deslocamento são 0 caso seja usado o operador de deslocamento à esquerda (<<) ou o operador de deslocamento à direita sem sinal (>>>). O operador de deslocamento à direita com sinal (>>) comporta-se de maneira diferente. Quando o operador >> é usado, os novos bits que entram na representação têm o mesmo valor do bit mais significativo antes do deslocamento. Por exemplo, se o bit mais significativo seja 1 (o número é negativo), bits com valor 1 são introduzidos no caso de um deslocamento.
<%-- Nao achei essa figura e portanto cortei essa parte. Para posterior revisao: ass. Ulisses O comportamento do operador (>>) está ilustrado na figura 3.Operadores de Comparação
Os operadores de comparação retornam um valor booleano e podem ser dividos nas seguintes categorias:
- operadores de comparação para tipos numéricos primitivos)
- operadores de comparação para objetos
- operadores de igualdade e desigualdade
Operadores de Comparação para Tipos Numéricos Primitivos: <, >, <=, >=
Estes operadores podem ser aplicados a qualquer tipo numérico primitivo e o tipo char e produzem um resultado booleano. Promoções aritméticas são realizadas na execução da operação, fazendo com que na comparação:
float f = 9.0; char c = ‘A’; f <= c; |
O valor de c (representado pelo valor Unicode 65) seja promovido para o valor float 65.0F. A comparação é então realizada entre dois valores float.
O Operador de Comparação para Objetos: instanceof
O operador instanceof testa a classe de um objeto. O operando da esquerda é a referência do objeto que se quer analisar e o operando da direita deve ser uma classe, interface ou tipo de array. O valor java.lang.Class não pode ser utilizado. Por exemplo, a sentença:
String str = “string”; str instanceof String; |
Retorna true.
O operador instanceof também pode ser usado para testar a referência de um array. Neste caso, são realizados dois testes: primeiro é verificado se o objeto é um array (isso pode ser realizado chamando-se o método isArray() da classe Class) e, sem seguida, é verificado se o tipo do array é de alguma subclasse do tipo do operando da direita. Considerando x um array de objetos Button a seguinte sentença retorna true:
if (x instanceof Component[]) |
Visto que Button é subclasse de Component.
Os Operadores de Igualdade e Desigualdade: == e !=
Os operdores == e != testam a igualdade ou desigualdade de dois valores, retornando um valor booleano. Quando o teste é realizado para tipos primitivos algumas promoções podem ocorrer fazendo com que, por exemplo, o valor float 10.0 seja considerado igual ao valor byte 10. Quando o teste é realizado para objetos, os valores comparados são as referências dos objetos, tipicamente endereços de memória. Esses operadores não devem ser usados para comparar o conteúdo dos objetos: eles apenas comparam se os objetos são o mesmo. Para fazer uma comparação semântica de objetos, o método equals(), definida por algumas classes, pode ser usado. Isso é ilustrado no exemplo abaixo:
1. String str1 = new String(“Hello”); 2. String str2 = new String(“Hello”); 3. System.out.println(str1==str2); 4. System.out.println(str1.equals(str2)); |
A instrução 3 imprime false porque str1 e str2 representam diferentes referências de objetos. A instrução 4, pelo contrário, imprime o valor true porque o que está sendo comparado é o conteúdo dos dois objetos.
Os Operadores Bit-a-Bit: &, ^ e |
Os operadores bit-a-bit &, ^ e | realizam as operações lógicas AND, XOR e OR bit-a-bit, respectivamente. Tais operações seguem as seguintes regras:
- para o operador AND: 1 AND 1 produz 1 e todos as demais combinações produzem 0;
- para o operador OR: 0 OR 0 produz 0 e todas as demais combinações produzem 1;
- para o operador XOR: 1 XOR 0 e 0 XOR 1 produzem 1 e as demais combinações produzem 0.
Todas essas operações são comutativas. As tabelas 3, 4 e 5 apresentam os possíveis resultados no uso destes operadores.
Quando os operadores &, ^ e | são aplicados a valores binários, eles executam operações bit-a-bit. Por exemplo, 0001011 AND 1001101 resulta no valor 0001001, 0001011 OR 1001101 resulta em 1001111 e 0001011 XOR 1001101 resulta em 1000110. Quando se trabalha com valores do tipo int, por exemplo, os valores são convertidos para binário, a operação é realizada bit-a-bit, e em seguida o resultado é convertido para int. Assim sendo, O seguinte código:
int a = 2&3; int b = 2|3; int c = 2^3; |
Produz em a o valor 2, em b o valor 3 e em c o valor 1.
Operações Booleanas
Os operadores &, ^ e | quando aplicados a operandos booleanos, comportam-se da mesma forma quando aplicados a operandos inteiros. A diferença é que quando a operação é realizada com valores inteiros, os valores são convertidos para binário e a operação é realizada bit-a-bit. Quando os operandos são booleanos, um valor booleano é tratado como um único bit. Assim, o valor false corresponde a um bit de valor 0 e o valor true corresponde a um bit de valor 1.
Operadores Lógicos de Curto-Circuito: && e ||
Os operadores lógicos de curto-circuito && e || realizam as operações lógicas AND e OR para valores booleanos, retratando comportamento semelhantes aos operadores & e |, salvo que eles não podem ser aplicados a tipos inteiros, apenas para valores booleanos. Não existe um operador XOR de curto-circuito e os operadores && e ||.
A principal diferença entre os operadores & e | e os operadores && e || é que estes fazem uma análise “curto-circuito” da expressão, e podem produzir resultados sem avaliar o operando da direita, tendo como base as regras de definição dos operadores AND e OR:
- para uma operação AND, se um operando é false, o resultado é false independente do valor do outro operando, ou seja, false AND x = false;
- para uma operação OR, se um operando é true, o resultado é true independente do valor do outro operando, ou seja, true OR x = true.
O seguinte trecho de código:
1. if (s!=null & s.length()>20)
System.out.print(s);
|
é semelhante ao trecho de código descrito abaxo:
2. if (s!=null && s.length()>20)
System.out.print(s);
|
Em ambos os códigos, o comando dentro da cláusula "if" não é executado caso o valor da variável "s" seja null. A diferença está no fato de que em 1 é lançada a exceção NullPointerException. Isso acontece porque o operador & analisa o valor dos dois operandos para depois retornar o valor da expressão. Considerando o valor de s null, o operando da esquerda é inicialmente analisado e o seu valor é false. Em seguida o operando da direita é analisado, com o intuito de realizar a operação & com os dois resultados. Então, a chamada s.length() é realizada e a exceção é lançada, uma vez que o valor de s é null. Em 2, o operando da esquerda é analisado e o seu valor é false, como mencionado anteriormente. Como a operação && é de curto-circuito, o operando da direita não é avaliado, uma vez que um operando false em uma operação AND produz um resultado false. Assim, o resultado da expressão (false) é retornado.
O Operador Condicional: ?:
O operador condicional ?:, comumente chamando operador ternário, representa uma forma simples de escrever condições a serem verificadas em uma única expressão. Por exemplo, se a, b e c são variáveis int e x é booleana, a sentença
a == x ? b : c; |
É equivalente ao código:
if (x) a = b; else a = c; |
Em uma expressão da forma a = x ? b : c:
- os tipos das expressões b e c devem ser compatíveis;
- o tipo da expressão x deve ser booleano;
- os tipos das expressões b e c devem ser compatíveis para uma declaração com o tipo de a;
- o valor armazenado em a deve ser b se x é true ou deve ser c se x é false.
O operador de Atribuição: =
O operador = atribui a uma variável um novo valor. Atribuições simples utilizam somente =. Outras atribuições podem ser da forma op=, onde op é um operador binário não-booleano, como + ou *. O comportamento de uma instrução da forma x op=y (1) é o mesmo da instrução x = x op y (2). Entretanto, há duas diferenças entre essas instruções:
- x é avaliado uma única vez em (1) e duas vezes em (2);
- operadores como o usado em (1) incluem casts implícitos. Considere o exemplo:
byte x = 2; x += 3; |
Na segunda instrução, um cast para byte seria necessário, uma vez que o resultado de uma adição entre int é no mínimo int. O cast é realizado implicitamente, sem a intervenção do programador.
O operador = produz um resultado. Isso pode ser analisado através do seguinte exemplo:
a = b = c = 0; |
A ordem de avaliação desta instrução é da direita para a esquerda, conforme discutido no início deste documento. Sendo assim, c = 0 é avaliado primeiro e produz um resultado, que é o valor do operando da direita, ou seja, 0. 0 é então armazenado em b e, similarmente, a expressão b = 0, produz o resultado 0, que é armazenado na variável a.
