ビット演算子を使用して複数の整数値をJavaの関数に渡す方法は?
-
22-07-2019 - |
質問
アプリケーションフレームワークでは、複数のInt値(通常はenumの代わりに使用される)を関数に渡すことができるフレームワークを見続けています。
例:
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
...
}
}
では、bitwise演算子を使用して渡される複数のint値を適切に評価するために、multiValueExampleにはどのようなロジックが必要ですか?
解決
値は2のべき乗でなければなりません
そのようにして、ビットごとのORをとっても情報を失うことはありません。
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。
これを行うことができます:
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.
}
他のヒント
すでに述べたように、ビット値の代わりに列挙の使用を検討してください。
Effective Java 2 によると:" Item 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ビットになるようにします。
int ONE = 0x1; //0001
int TWO = 0x2; //0010
int THREE = 0x4; //0100
int FOUR = 0x8; //1000
次に、ビット単位のORを使用して値を組み合わせ、ビット単位のANDを使用して設定値をテストします。
int test_value = (ONE | FOUR); //-> 1001
bool has_one = (test_value & ONE) != 0; //-> 1001 & 0001 -> 0001 -> true
組み合わせた値| (論理OR [||]ではなくバイナリOR)は、ビット表現で「1」が重複していてはなりません。たとえば、
ONE = 0x1 = 0000 0001
TWO = 0x2 = 0000 0010
THREE = 0x3 = 0000 0011
FOUR = 0x4 = 0000 0100
次に、1と2を組み合わせることができます。例:
ONE | TWO = 0000 0011
ただし、1つを区別することはできません|ビットが重複しているため、3から2。したがって、組み合わせた数値は2の累乗である必要があり、ORをとったときに重ならないようにします。数値が「値」に渡されたかどうかをテストするには、次のようにします。
if (values & ONE) {
// ... then ONE was set
}
これがなぜ、どのように機能するかをよりよく理解するために、バイナリ表現とロジックについて少し読むことをお勧めします。適切な場所は、アセンブリオブアートの第3章。
もしそれらが2のべき乗であれば、「表示」のようなことをするでしょう。以下のコードのメソッド。
こちらのトピックに関するウィキペディアのリンクもご覧ください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();
}
}
ビットマスクを使用することは、すべてのビットがカウントされるときに一般的でした。今日これを行う別の方法は、より簡単に操作および拡張できる列挙を使用することです。
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.
}
}
}
最初に、ビットごとの比較を行う方法で値を定義することはできません。代わりに、異なるビットを設定します。
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}"
ビット単位の操作に関するJavaチュートリアルの章は
にありますhttp://java.sun.com/docs /books/tutorial/java/nutsandbolts/op3.html
非常に簡潔ですが、参考になります。