2009-03-15 6 views
13

Nei framework dell'applicazione continuo a vedere framework che consentono di passare in più valori Int (generalmente utilizzati al posto di un enum) in una funzione.Come utilizzare un operatore bit per bit per passare più valori Integer in una funzione per Java?

Ad esempio:

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

Quindi, quale logica dovrebbe esistere in multiValueExample per me per valutare correttamente più valori int vengono passati utilizzando l'operatore bit per bit?

+0

chiarire. Non capisco. Quelli non sono più valori. Valori.ONE | Valori.THREE | Values.FIVE = 0x7f020006, giusto? E qual è lo scopo dei bit senza nome? –

+0

C'è un motivo specifico per cui si desidera utilizzare operazioni bit a bit? Le soluzioni enum/EnumSet sono più chiare e più simili a Java. –

risposta

30

I suoi valori devono essere potenze di 2.

In questo modo, non si perde alcuna informazione quando si bit a bit-o.

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; 

ecc

allora si può fare questo:

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

Non dovrebbe essere un bit per bit AND (singolo e)? – Hamid

+2

Credo che tu intenda poteri di 2, non multipli di 2. Non puoi distinguere 2 | 4 da 6. Inoltre, && è AND logico, non binario, quindi valuterà sempre true. –

+0

@Hamid e Joao: grazie per le correzioni. –

3

primo luogo, non è possibile definire i valori in questo modo di fare paragoni bit a bit. Invece, impostare diversi bit:

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 

In secondo luogo, si dovrebbe probabilmente utilizzare java.util.BitSet per questo tipo di operazioni:

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

C'è qualcosa per cui Java non ha una classe? =) –

+1

Sì! http://stackoverflow.com/questions/639035/making-theperfect-programming-language/639042#639042;) –

+0

haha, quella funzione esiste solo in Python (http://xkcd.com/353/). =) –

4

I valori si combinano con | (OR binario, non logico OR [che è ||]) non deve avere "1" sovrapposti nella loro rappresentazione bit. Ad esempio,

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

Quindi è possibile combinare uno e due, per esempio:

ONE | TWO = 0000 0011 

Ma non si può distinguere ONE | DUE da TRE, perché ci sono bit sovrapposti. I numeri che si combinano dovrebbero quindi avere il potere di due, in modo tale che non si sovrappongano quando OR'ed insieme. Per verificare se un numero è stata approvata in "valori", lo fanno:

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

per capire meglio perché e come funziona, vi consiglio di leggere un po 'sulla rappresentazione binaria e la logica. Un buon posto è Chapter 3 of the Art of Assembly.

5

È possibile impostare i valori interi come potenze di due in modo che ciascun valore enumerato sia un singolo bit nella rappresentazione binaria.

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

quindi si utilizza OR bit a bit di coniugare valori e bit a bit e per testare i valori impostati.

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

Beh, se sono potenze di 2 si dovrebbe fare qualcosa come il metodo "display" nel codice qui sotto.

Here is a link in wikipedia sull'argomento, che dovrebbe spiegare il motivo per cui si desiderano i poteri di 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

L'utilizzo di maschere di bit era comune quando ogni bit veniva contato. Un altro modo per farlo oggi è usare le enumerazioni con le più semplici da manipolare ed estendere.

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

Come già accennato, si consideri l'uso di enumerazioni anziché di bit.

Secondo Effective Java 2: "Articolo 32: Uso EnumSet al posto di campi di bit"

L'utilizzo di EnumSet è molto efficace per l'utilizzo della memoria e molto conveniente.

Ecco un esempio:

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 soluzione più simile a Java –

+0

Sì, grazie per questa soluzione. Sfortunatamente sto lavorando con la tecnologia mobile in cui le enumerazioni hanno un grande successo in termini di gestione della memoria. Come tale, sto usando il funzionamento bit a bit per migliorare la preformance. – AtariPete

+0

D'accordo, in un'applicazione mobile ha senso. –

Problemi correlati