Operadores Java Bitwise

Operadores Java Bitwise

1. Visão geral

Operators são usados ​​na linguagem Java para operar em dados e variáveis.

Neste tutorial, vamos explorar Operadores Bitwise e como eles funcionam em Java.

2. Operadores bit a bit

Bitwise operators work on binary digits or bits of input values. Podemos aplicá-los aos tipos inteiros -long, int, short, char,ebyte.

Antes de explorar os diferentes operadores bit a bit, vamos primeiro entender como eles funcionam.

Operadores bit a bit trabalham em um equivalente binário de números decimais e executam operações neles bit a bit de acordo com o operador fornecido:

  • Primeiro, os operandos são convertidos em sua representação binária

  • Em seguida, o operador é aplicado a cada número binário e o resultado é calculado

  • Finalmente, o resultado é convertido novamente em sua representação decimal

Vamos entender com um exemplo; vamos pegar doisintegers:

int value1 = 6;
int value2 = 5;

A seguir, vamos aplicar um operador OR bit a bit a estes números:

int result = 6 | 5;

Para executar esta operação, primeiro, a representação binária desses números será calculada:

Binary number of value1 = 0110
Binary number of value2 = 0101

Em seguida, a operação será aplicada a cada bit. O resultado retorna um novo número binário:

0110
0101
-----
0111

Finalmente, o resultado0111 will ser convertido de volta para decimal que é igual a7:

result : 7

Os operadores bit a bit são ainda classificados como operadores lógicos e de mudança bit a bit. Vamos agora examinar cada tipo.

3. Operadores lógicos bit a bit

Os operadores lógicos bit a bit são AND (&), OR (|), XOR (^) e NOT (~).

3.1. OR bit a bit (|)

O operador OR compara cada dígito binário de dois inteiros e retorna 1 se algum deles for 1.

Isso é semelhante ao || operador lógico usado com booleanos. Quando dois booleanos são comparados, o resultado étrue se algum deles fortrue. Da mesma forma, a saída é 1 quando qualquer um deles for 1.

Vimos um exemplo desse operador na seção anterior:

@Test
public void givenTwoIntegers_whenOrOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int value2 = 5;
    int result = value1 | value2;
    assertEquals(7, result);
}

Vejamos a representação binária desta operação:

0110
0101
-----
0111

Aqui, podemos ver que usar OR, 0 e 0 resultará em 0, enquanto qualquer combinação com pelo menos 1 resultará em 1.

3.2. AND bit a bit (&)

O operador AND compara cada dígito binário de dois inteiros e retorna 1 se ambos forem 1, caso contrário, ele retorna 0.

Isso é semelhante ao operador && com valoresboolean. Quando os valores de doisbooleans sãotrue, o resultado de uma operação && étrue.

Vamos usar o mesmo exemplo acima, exceto que agora usamos o operador & em vez do | operador:

@Test
public void givenTwoIntegers_whenAndOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int value2 = 5;
    int result = value1 & value2;
    assertEquals(4, result);
}

Vejamos também a representação binária desta operação:

0110
0101
-----
0100

0100 é4 em decimal, portanto, o resultado é:

result : 4

3.3. XOR bit a bit (^)

The XOR operator compares each binary digit of two integers and gives back 1 if both the compared bits are different. Isso significa que se os bits de ambos os inteiros forem 1 ou 0, o resultado será 0; caso contrário, o resultado será 1:

@Test
public void givenTwoIntegers_whenXorOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int value2 = 5;
    int result = value1 ^ value2;
    assertEquals(3, result);
}

E a representação binária:

0110
0101
-----
0011

0011  é 3 em decimal, portanto, o resultado é:

result : 3

3.4. COMPLEMENTO bit a bit (~)

Operador Bitwise Not ou Complement significa simplesmente a negação de cada bit do valor de entrada. Leva apenas um número inteiro e é equivalente ao! operador.

Este operador altera cada dígito binário do número inteiro, o que significa que todos os 0 se tornam 1 e todos os 1 se tornam 0. O ! O operador funciona de maneira semelhante para os valores deboolean: ele inverte os valores deboolean detrue parafalse e vice-versa.

Agora vamos entender com um exemplo como encontrar o complemento de um número decimal.

Vamos fazer o complemento de valor1 = 6:

@Test
public void givenOneInteger_whenNotOperator_thenNewDecimalNumber() {
    int value1 = 6;
    int result = ~value1;
    assertEquals(-7, result);
}

O valor em binário é:

value1 = 0000 0110

Ao aplicar o operador complemento, o resultado será:

0000 0110 -> 1111 1001

Este é o complemento do número decimal 6. E como o primeiro bit (mais à esquerda) é 1 em binário, significa que o sinal é negativo para o número armazenado.

Agora, como os números são armazenados como complemento de 2, primeiro precisamos encontrar o complemento de 2 e depois converter o número binário resultante em um número decimal:

1111 1001 -> 0000 0110 + 1 -> 0000 0111

Finalmente, 0000 0111 é 7 em decimal. Como o bit do sinal foi 1, como mencionado acima, a resposta resultante é:

result : -7

3.5. Tabela de operadores bit a bit

Vamos resumir o resultado dos operadores que vimos até agora em uma tabela de comparação:

A    B   A|B A&B A^B ~A
0   0   0   0   0   1
1   0   1   0   1   0
0   1   1   0   1   1
1   1   1   1   0   0

4. Operadores de deslocamento bit a bit

Os operadores de deslocamento binário deslocam todos os bits do valor de entrada para a esquerda ou direita com base no operador de deslocamento.

Vamos ver a sintaxe para esses operadores:

value  

O lado esquerdo da expressão é o número inteiro que é deslocado e o lado direito da expressão indica o número de vezes que ele deve ser deslocado.

Os operadores de turno bit a bit são classificados ainda como operadores de turno bit a esquerda e bit a direita.

4.1. Turno à esquerda assinado [<<]

O operador de deslocamento para a esquerda desloca os bits para a esquerda pelo número de vezes especificado pelo lado direito do operando. Após o deslocamento para a esquerda, o espaço vazio à direita é preenchido com 0.

Outro ponto importante a notar é queshifting a number by one is equivalent to multiplying it by 2, or, in general, left shifting a number by n positions is equivalent to multiplication by 2^n.

Vamos tomar o valor 12 como valor de entrada.

Agora, vamos movê-lo 2 lugares para a esquerda (12 << 2) e ver qual será o resultado final.

O equivalente binário de 12 é 00001100. Depois de mudar para a esquerda por 2 casas, o resultado é 00110000, o equivalente a 48 em decimal:

@Test
public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber() {
    int value = 12;
    int leftShift = value << 2;
    assertEquals(48, leftShift);
}

Isso funciona da mesma forma para um valor negativo:

@Test
public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber() {
    int value = -12;
    int leftShift = value << 2;
    assertEquals(-48, leftShift);
}

4.2. Shift direito assinado [>>]

The right shift operator shifts all the bits to the right. O espaço vazio no lado esquerdo é preenchido dependendo do número de entrada:

  • Quando um número de entrada é negativo, onde o bit mais à esquerda é 1, os espaços vazios serão preenchidos com 1

  • Quando um número de entrada é positivo, onde o bit mais à esquerda é 0, os espaços vazios serão preenchidos com 0

Vamos continuar o exemplo usando 12 como entrada.

Agora, vamos movê-lo 2 lugares para a direita (12 >> 2) e ver qual será o resultado final.

O número de entrada é positivo; portanto, depois de mudar para a direita em 2 casas, o resultado é 0011, que é 3 em decimal:

@Test
public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() {
    int value = 12;
    int rightShift = value >> 2;
    assertEquals(3, rightShift);
}

Além disso, para um valor negativo:

@Test
public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber() {
    int value = -12;
    int rightShift = value >> 2;
    assertEquals(-3, rightShift);
}

4.3. Deslocamento à direita não assinado [>>>]

Este operador é muito semelhante ao operador de turno certo assinado. The only difference is that the empty spaces in the left are filled with 0 irrespective of whether the number is positive or negative. Portanto, o resultado será sempre um número inteiro positivo.

Vamos deslocar para a direita o mesmo valor de 12:

@Test
public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() {
    int value = 12;
    int unsignedRightShift = value >>> 2;
    assertEquals(3, unsignedRightShift);
}

E agora, o valor negativo:

@Test
public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber() {
    int value = -12;
    int unsignedRightShift = value >>> 2;
    assertEquals(1073741821, unsignedRightShift);
}

5. Diferença entre operadores bit a bit e lógicos

Existem algumas diferenças entre os operadores bit a bit que discutimos aqui e os operadores lógicos mais comumente conhecidos.

Primeiro,logical operators work on boolean expressionse retornam valoresboolean (true oufalse),, enquantobitwise operators work on binary digits de valores inteiros (long, int, short, char,ebyte) e retorna um inteiro.

Além disso, os operadores lógicos sempre avaliam a primeira expressãoboolean e, dependendo de seu resultado e do operador usado, podem ou não avaliar a segunda. Por outro lado,bitwise operators always evaluate both operands.

Finalmente, operadores lógicos são usados ​​na tomada de decisões com base em várias condições, enquanto operadores bit a bit trabalham em bits e realizam operações bit a bit.

6. Casos de Uso

Alguns casos de uso em potencial de operadores bit a bit são:

  • Pilhas de comunicação em que os bits individuais no cabeçalho anexado aos dados significam informações importantes

  • Nos sistemas embarcados, para definir / limpar / alternar apenas um bit de um registro específico sem modificar os bits restantes

  • Para criptografar dados por problemas de segurança usando o operador XOR

  • Na compactação de dados, convertendo dados de uma representação para outra, para reduzir a quantidade de espaço usado

7. Conclusão

Neste tutorial, aprendemos sobre os tipos de operadores bit a bit e como eles são diferentes dos operadores lógicos. Também vimos alguns casos de uso em potencial para eles.

Todos os exemplos de código neste artigo estão disponíveisover on GitHub.