2009-03-15 8 views
13

En frameworks de aplicaciones sigo viendo frameworks que le permiten pasar múltiples valores Int (generalmente utilizados en lugar de una enumeración) a una función.¿Cómo usar un operador bit a bit para pasar múltiples valores enteros a una función para Java?

Por ejemplo:

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 
     ... 
    } 
} 

Entonces, ¿qué lógica debe existir en multiValueExample para mí para evaluar adecuadamente múltiples valores int que se pasa en el uso del operador de bits?

+0

favor aclarar. No entiendo. Esos no son valores múltiples. Valores.ONE | Valores.THREE | Valores.FIVE = 0x7f020006, ¿verdad? ¿Y cuál es el propósito de los bits sin nombre? –

+0

¿Hay alguna razón específica por la que desee usar operaciones bit a bit? Las soluciones enum/EnumSet son más claras y más parecidas a Java. –

Respuesta

30

Sus valores deben ser potencias de 2.

De esa manera, no se pierde ninguna información cuando bit a bit-O ellos.

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.

entonces usted puede hacer esto:

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. 
} 
+0

¿No debería ser eso un AND de Bitwise (solo y)? – Hamid

+2

Creo que te refieres a poderes de 2, no a múltiplos de 2. No puedes distinguir 2 | 4 de 6. Además, && es lógico AND, no binario Y, por lo que siempre se evaluará como verdadero. –

+0

@Hamid y Joao: gracias por las correcciones. –

3

En primer lugar, no se puede definir los valores de esa manera hacer comparaciones a nivel de bit. En su lugar, establecer diferentes bits:

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 

En segundo lugar, es probable que debe utilizar java.util.BitSet para este tipo de operaciones:

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}" 
+0

¿Hay algo para lo que Java no tenga una clase? =) –

+1

¡Sip! http://stackoverflow.com/questions/639035/making-the-perfect-programming-language/639042#639042;) –

+0

jaja, esa función solo existe en Python (http://xkcd.com/353/). =) –

4

Los valores que se combinan con | (OR binario, no O lógico [que es ||]) no debe tener "1" s superpuestos en su representación de bit. Por ejemplo,

ONE = 0x1 = 0000 0001 
TWO = 0x2 = 0000 0010 
THREE = 0x3 = 0000 0011 
FOUR = 0x4 = 0000 0100 

Entonces usted puede combinar uno y dos, por ejemplo:

ONE | TWO = 0000 0011 

pero no se puede distinguir una | DOS de TRES, porque hay bits superpuestos. Los números que combine deben ser potencias de dos, de modo que no se superpongan cuando se combinan. Para probar si un número se aprobó en los "valores", hacer:

if (values & ONE) { 
    // ... then ONE was set 
} 

Para comprender mejor por qué y cómo funciona esto, le recomiendo que lea un poco en representación binaria y la lógica. Un buen lugar es Chapter 3 of the Art of Assembly.

5

Configure los valores enteros como potencias de dos para que cada valor enumerado sea un bit único en la representación binaria.

int ONE = 0x1; //0001 
int TWO = 0x2; //0010 
int THREE = 0x4; //0100 
int FOUR = 0x8; //1000 

Luego se usa el bit O para combinar los valores y AND a nivel de bits para probar los valores establecidos.

int test_value = (ONE | FOUR); //-> 1001 
bool has_one = (test_value & ONE) != 0; //-> 1001 & 0001 -> 0001 -> true 
3

Bueno, si son potencias de 2, harías algo así como el método de "pantalla" en el siguiente código.

Here is a link in wikipedia sobre el tema, así que debería explicar por qué quiere potencias 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(); 
    } 
} 
3

El uso de máscaras de bits era popular cuando se contaban todos los bits. Otra forma de hacer esto hoy es usar enums con son más simples de manipular y extender.

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. 
     } 
    } 
} 
9

Como ya se ha mencionado, considere el uso de enumeraciones en lugar de valores de bit.

Según Effective Java 2: "Artículo 32: Uso EnumSet en lugar de campos de bits"

Uso de EnumSet es bastante efectiva para el uso de memoria y muy conveniente.

Aquí se muestra un ejemplo:

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"); 
    } 
    } 
} 
+2

+1 la solución más similar a Java –

+0

Sí, gracias por esta solución. Lamentablemente, estoy trabajando con la tecnología móvil, donde las enumeraciones reciben un gran impacto en términos de gestión de la memoria. Como tal, estoy usando la operación bit a bit para mejorar el rendimiento. – AtariPete

+0

De acuerdo, en una aplicación móvil tiene sentido. –

Cuestiones relacionadas