Como usar um operador bit a bit para passar vários valores inteiros em uma função para Java?
-
22-07-2019 - |
Pergunta
Em frameworks de aplicação Eu continuo vendo estruturas que permitem que você passar em vários valores Int (geralmente usado no lugar de um enum) em uma função.
Por exemplo:
public class Example
{
public class Values
{
public static final int ONE = 0x7f020000;
public static final int TWO = 0x7f020001;
public static final int THREE = 0x7f020002;
public static final int FOUR = 0x7f020003;
public static final int FIVE = 0x7f020004;
}
public static void main(String [] args)
{
// should evaluate just Values.ONE
Example.multiValueExample(Values.ONE);
// should evalueate just values Values.ONE, Values.THREE, Values.FIVE
Example.multiValueExample(Values.ONE | Values.THREE | Values.FIVE);
// should evalueate just values Values.TWO , Values.FIVE
Example.multiValueExample(Values.TWO | Values.FIVE);
}
public static void multiValueExample(int values){
// Logic that properly evaluates bitwise values
...
}
}
Então, o que a lógica deve existir em multiValueExample para mim para avaliar adequadamente vários valores int sendo passado usando o operador bit a bit?
Solução
Seus valores devem ser potências de 2.
Dessa forma, você não perca nenhuma informação quando você bitwise-OR-los.
public static final int ONE = 0x01;
public static final int TWO = 0x02;
public static final int THREE = 0x04;
public static final int FOUR = 0x08;
public static final int FIVE = 0x10;
etc.
Em seguida, você pode fazer isso:
public static void main(String [] args) {
Example.multiValueExample(Values.ONE | Values.THREE | Values.FIVE);
}
public static void multiValueExample(int values){
if ((values & Values.ONE) == Values.ONE) {
}
if ((values & Values.TWO) == Values.TWO) {
}
// etc.
}
Outras dicas
Como já foi mencionado, considere o uso de enums em vez de valores de bit.
De acordo com a Effective Java 2 : "Item 32: Use EnumSet em vez de campos de bits "
O uso do EnumSet é bastante eficaz para o uso de memória e muito conveniente.
Aqui está um exemplo:
package enums;
import java.util.EnumSet;
import java.util.Set;
public class Example {
public enum Values {
ONE, TWO, THREE, FOUR, FIVE
}
public static void main(String[] args) {
// should evaluate just Values.ONE
Example.multiValueExample(EnumSet.of(Values.ONE));
// should evalueate just values Values.ONE, Values.THREE, Values.FIVE
Example.multiValueExample(EnumSet.of(Values.ONE, Values.THREE, Values.FIVE));
// should evalueate just values Values.TWO , Values.FIVE
Example.multiValueExample(EnumSet.of(Values.TWO, Values.FIVE));
}
public static void multiValueExample(Set<Values> values) {
if (values.contains(Values.ONE)) {
System.out.println("One");
}
// Other checks here...
if (values.contains(Values.FIVE)) {
System.out.println("Five");
}
}
}
configuração Você os valores inteiros para ser potências de dois para que cada valor enumerado é um único bit na representação binária.
int ONE = 0x1; //0001
int TWO = 0x2; //0010
int THREE = 0x4; //0100
int FOUR = 0x8; //1000
Em seguida, você usa bit a bit OR para combinar os valores e bit a bit E para valores conjunto de teste.
int test_value = (ONE | FOUR); //-> 1001
bool has_one = (test_value & ONE) != 0; //-> 1001 & 0001 -> 0001 -> true
Os valores que combinam com | (Binário OR, não lógica OU [que é ||]) não deve ter sobreposição "1" s na sua representação de bits. Por exemplo,
ONE = 0x1 = 0000 0001
TWO = 0x2 = 0000 0010
THREE = 0x3 = 0000 0011
FOUR = 0x4 = 0000 0100
Em seguida, você pode combinar um e dois, por exemplo:
ONE | TWO = 0000 0011
Mas você não pode distinguir um | DOIS a partir de três, porque não se sobrepõem pedaços. Os números que combinam deve ser, portanto, potências de dois, de modo que eles não se sobreponham quando OR'ed juntos. Para testar se um número foi passado em "valores", fazer:
if (values & ONE) {
// ... then ONE was set
}
Para entender melhor por que e como isso funciona, eu recomendo que você leia um pouco sobre a representação binária e lógica. Um bom lugar é capítulo 3 do Art of Assembly .
Bem, se eles são potências de 2 que você faria algo como o método de "display" no código abaixo.
Aqui está um link na wikipedia sobre o tema, bem como que deve explicar por que você quer potências de 2.
public class Main
{
private static final int A = 0x01;
private static final int B = 0x02;
private static final int C = 0x04;
public static void main(final String[] argv)
{
display(A);
display(B);
display(C);
display(A | A);
display(A | B);
display(A | C);
display(B | A);
display(B | B);
display(B | C);
display(C | A);
display(C | B);
display(C | C);
display(A | A | A);
display(A | A | B);
display(A | A | C);
display(A | B | A);
display(A | B | B);
display(A | B | C);
display(A | C | A);
display(A | C | B);
display(A | C | C);
display(B | A | A);
display(B | A | B);
display(B | A | C);
display(B | B | A);
display(B | B | B);
display(B | B | C);
display(B | C | A);
display(B | C | B);
display(B | C | C);
display(C | A | A);
display(C | A | B);
display(C | A | C);
display(C | B | A);
display(C | B | B);
display(C | B | C);
display(C | C | A);
display(C | C | B);
display(C | C | C);
}
private static void display(final int val)
{
if((val & A) != 0)
{
System.out.print("A");
}
if((val & B) != 0)
{
System.out.print("B");
}
if((val & C) != 0)
{
System.out.print("C");
}
System.out.println();
}
}
Usando máscaras de bits eram populares quando cada bit contados. Outra maneira de fazer isso hoje é enums uso com são mais simples de manipular e estender.
import static Example.Values.*;
import java.util.Arrays;
public class Example {
public enum Values { ONE, TWO, THREE, FOUR, FIVE }
public static void main(String [] args) {
// should evaluate just Values.ONE
multiValueExample(ONE);
// should evaluate just values Values.ONE, Values.THREE, Values.FIVE
multiValueExample(ONE, THREE, FIVE);
// should evaluate just values Values.TWO , Values.FIVE
multiValueExample(TWO, FIVE);
}
public static void multiValueExample(Values... values){
// Logic that properly evaluates
System.out.println(Arrays.asList(values));
for (Values value : values) {
// do something.
}
}
}
Em primeiro lugar, você não pode definir os valores que maneira de fazer comparações bit a bit. Em vez disso, definir diferentes pedaços:
public static final int ONE = 0x1; // First bit is set
public static final int TWO = 0x2; // Second bit is set
public static final int THREE = 0x4; // Third bit is set
public static final int FOUR = 0x8; // Fourth bit is set
public static final int FIVE = 0x10; // Fifth bit is set
Em segundo lugar, você provavelmente deve estar usando java.util.BitSet para esses tipos de operações:
BitSet bits = new BitSet(5);
bits.set(2);
bits.set(4);
System.out.println("these bits are set: " + bits);
// Prints "these bits are set: {2, 4}"
BitSet otherBits = new BitSet(5);
otherBits.set(3);
otherBits.set(4);
System.out.println("these bits are set: " + bits.or(otherBits));
// Prints "these bits are set: {2, 3, 4}"
O capítulo Java Tutorial em operações bit a bit estão no
http://java.sun.com/docs /books/tutorial/java/nutsandbolts/op3.html
É muito conciso, mas bom para referência.