2009-03-15 10 views
13

В инфраструктурах приложений я все время вижу рамки, которые позволяют передавать в функции несколько значений Int (обычно используемых вместо enum).Как использовать побитовый оператор для передачи нескольких значений Integer в функцию для Java?

Например:

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

Так что логика должна существовать в multiValueExample для меня, чтобы правильно оценить несколько ИНТ значений, передаваемых при помощи оператора побитового?

+0

Просьба уточнить. Я не понимаю. Это не множественные значения. Значения.ONE | Значения.THREE | Значения.FIVE = 0x7f020006, правильно? И в чем цель безымянных бит? –

+0

Есть ли конкретная причина, по которой вы хотите использовать побитовые операции? Решения enum/EnumSet являются понятными и более похожими на Java. –

ответ

30

Ваши ценности должны быть полномочия 2.

Таким образом, вы не потеряете какую-либо информацию, когда вы побитовое ИЛИ им.

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; 

и т.д.

Тогда вы можете сделать это:

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

Не должно быть побитовое И (одно и то же)? – Hamid

+2

Я считаю, что вы имеете в виду полномочия 2, а не кратные 2. Вы не можете отличить 2 | 4 из 6. Кроме того, && является логическим И, а не двоичным И, поэтому он всегда будет оценивать значение true. –

+0

@ Хамид и Жоао: спасибо за исправления. –

3

Во-первых, вы не можете определить значения таким образом, чтобы сделать побитовое сравнение. Вместо этого, устанавливать различные биты:

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 

Во-вторых, вы, вероятно, следует с помощью java.util.BitSet для такого рода операций:

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

Есть ли что-нибудь, для чего у Java нет класса? =) –

+1

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

+0

haha, эта функция существует только в Python (http://xkcd.com/353/). =) –

4

Значения, сочетающих с | (двоичный OR, а не логический ИЛИ [который является ||]) не должен перекрывать «1» в их представлении бит. Например,

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

Тогда вы можете комбинировать один и два, например:

ONE | TWO = 0000 0011 

Но вы не можете отличить одно | ДВА от ТРИ, потому что есть перекрывающиеся биты. Таким образом, числа, которые вы объединяете, должны быть равны двум, чтобы они не перекрывались, когда OR'ed вместе. Чтобы проверить, является ли число было принято в «ценности», сделайте следующее:

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

Чтобы лучше понять, почему и как это работает, я рекомендую вам прочитать немного о двоичном представлении и логике. Хорошее место - Chapter 3 of the Art of Assembly.

5

Вы устанавливаете значения целых чисел равными двум, чтобы каждое перечислимое значение представляло собой один бит в двоичном представлении.

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

Затем вы используете побитовое ИЛИ для объединения значений и побитового И для проверки установленных значений.

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

Ну, если они имеют силу 2, вы бы сделали что-то вроде метода «отображения» в приведенном ниже коде.

Here is a link in wikipedia по теме, которая также должна объяснить, почему вы хотите, чтобы силы были 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

Использование бит-масок было популярным, когда каждый бит подсчитывался. Другой способ сделать это сегодня - это использовать перечисления, которые проще манипулировать и расширять.

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

Как уже упоминалось, рассмотрите возможность использования перечислений вместо битовых значений.

По Effective Java 2: «Пункт 32: Используйте EnumSet вместо битовых полей»

Использование EnumSet является весьма эффективным для использования памяти и очень удобно.

Вот пример:

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 самое Java-подобное решение –

+0

Да, спасибо за это решение. К сожалению, я работаю с мобильными технологиями, где перечисления занимают довольно много места с точки зрения управления памятью. Как таковой, я использую побитовую операцию для улучшения предварительной работы. – AtariPete

+0

Согласитесь, в мобильном приложении это имеет смысл. –