最初に、、、がビット演算子であることを学びました&
。|
そして^
今、誰かがそれらを論理演算子として言及しました。、、&&
私||
は完全に混乱しています-同じ演算子には2つの名前がありますか?すでに論理演算子、、がありますが&&
、||
なぜ、、を使用する&
の|
です^
か?
4 に答える
Java演算子&
、|
および^
は、オペランドのタイプに応じて、ビット演算子または論理演算子のいずれかです。オペランドが整数の場合、演算子はビット単位です。それらがブール値である場合、演算子は論理的です。
そして、これは私がこれを言っているだけではありません。JLSは、これらの演算子についてもこのように説明しています。JLS15.22を参照してください。
(これは+
、オペランドのタイプに応じて、加算または文字列連結のいずれかを意味するのと同じです。または、花またはシャワーのアタッチメントを意味する「バラ」のようになります。または、毛皮のような動物またはUNIXを意味する「猫」のようになります。コマンド。単語は、さまざまなコンテキストでさまざまな意味を持ちます。これは、プログラミング言語で使用される記号にも当てはまります。)
すでに論理演算子
&&
、、を||
使用する理由&
、、?|
^
最初の2つの場合は、オペランドがいつ/評価されるかに関して、演算子のセマンティクスが異なるためです。異なる状況では、2つの異なるセマンティクスが必要です。例えば
boolean res = str != null && str.isEmpty();
対
boolean res = foo() & bar(); // ... if I >>need<< to call both methods.
^
短絡が発生しても意味がないため、オペレータには短絡に相当するものはありません。
言語参照を持つことは1つのことであり、それを正しく解釈することは別のことです。
私たちは物事を正しく解釈する必要があります。
Java&
がビット単位で論理的であると文書化したとしても&
、太古の昔から、C以来、論理演算子のモジョを実際に失うことはなかったという議論をすることができます。つまり、何より&
もまず、本質的に論理演算子です(その時点で短絡していないもの)
&
論理演算として字句的+論理的に解析します。
ポイントを証明するために、これらの行は両方とも、Cから現在まで(Java、C#、PHPなど)同じように動作します。
if (a == 1 && b)
if (a == 1 & b)
つまり、コンパイラはそれらを次のように解釈します。
if ( (a == 1) && (b) )
if ( (a == 1) & (b) )
そして、両方の変数a
とb
が両方とも整数であっても。これ...
if (a == 1 & b)
...引き続き次のようにインタプリタされます:
if ( (a == 1) & (b) )
したがって、これにより、整数/ブール値の二重性を促進しない言語(JavaやC#など)でコンパイルエラーが発生します。
if (a == 1 & b)
実際、上記のコンパイルエラーでは&
、論理(非短絡)操作mojoを失わない引数を作成することもでき、JavaはCの伝統を継続し&
て論理操作にしていると結論付けることができます。したがって、これは逆であると言えます。つまり、&
ビット単位の操作として再利用できます(括弧を適用することにより)。
if ( a == (1 & b) )
つまり、別のパラレルユニバースでは、&
式をビットマスク操作にする方法を誰かが尋ねることができます。
&
次のコンパイル方法は、ビット演算であるJLSで読みました。aとbはどちらも整数ですが、次のビット演算がJavaでのコンパイルエラーである理由はわかりません。if(a == 1&b)
またはこの種の質問:
以下がコンパイルされなかった理由、
&
両方のオペランドが整数の場合のビット演算であるJLSを読み取りました。aとbはどちらも整数ですが、次のビット演算がJavaでのコンパイルエラーである理由はわかりません。if(a == 1&b)
実際、Javaでそのマスキングイディオムを実行する方法を尋ねた上記の質問と同様の既存のスタックオーバーフローの質問がすでに存在する場合でも、私は驚かないでしょう。
言語による論理演算の解釈をビット単位にするために、これを行う必要があります(すべての言語、C、Java、C#、PHPなど)。
if ( a == (1 & b) )
したがって、質問に答えるのは、JLSがそのように定義したからではなく、Java(およびCに触発された他の言語)の&
演算子がすべての目的のためであり、目的は依然として論理演算子であり、Cの構文とセマンティクスを保持しているためです。それは、C以来、太古の昔から、私が生まれる前からのやり方です。
物事は偶然に起こらない、JLS 15.22は偶然に起こらなかった、それの周りには深い歴史があります。
言語が導入されていない別のパラレルユニバースでは、論理演算に&&
引き続き使用&
します。今日、質問をすることもあります。
それは本当ですか、ビット単位の
&
演算に論理演算子を使用できますか?
&
オペランドが整数であるかどうか、ブール値であるかどうかは関係ありません。それはまだ論理演算子であり、短絡されていない演算子です。実際、Java(およびCでも)でビット単位の演算子になるように強制する唯一の方法は、括弧で囲むことです。すなわち
if ( a == (1 & b) )
考えてみてください&&
。C言語(およびその構文とセマンティクスをコピーした言語)が紹介されていなければ、誰もが今尋ねている可能性があります。
&
ビット演算の使用方法は?
要約すると、何よりもまずJava&
は本質的に論理演算子(短絡されていない演算子)であり、オペランドを気にせず、両方のオペランドが整数(例:マスキングイディオム)。括弧を適用することによってのみ、ビット単位の操作になるように強制できます。JavaはCの伝統を引き継いでいます
Javaの&
オペランド(以下のサンプルコードの整数1と整数変数b
)が両方とも整数である場合、Javaが実際にビット演算である場合、これはコンパイルする必要があります。
int b = 7;
int a = 1;
if (a == 1 & b) ...
それら(&
および|
)は、論理演算子とビット演算子の2つの目的で使用されていました。新生児C(Javaがパターン化された言語)をチェックする&
と|
、論理演算子として使用されていました。
ただし、同じステートメントでビット単位の演算を論理演算から明確にすることは非常に混乱するため、デニス・リッチーは論理演算子用に別の演算子(&&
および)を作成するように促されました。||
ここで新生児帝王切開を確認してください:http: //cm.bell-labs.com/who/dmr/chist.html
ビット演算子を論理演算子として引き続き使用できます。保持されている演算子の優先順位は、その証拠です。新生児Cの論理演算子としてのビット演算子の過去の生活の歴史を読みます
証拠については、論理演算子とビット演算子の比較についてブログに投稿しました。実際のプログラムでそれらを対比しようとすると、いわゆるビット演算子が依然として論理演算子であることは自明です: http ://www.anicehumble.com/2012/05/operator-precedence-101.html
また、Cの論理演算子のポイントは何ですか?に関するあなたの質問に関連する質問に答えました。
したがって、短絡論理演算子の非短絡バージョンではありますが、ビット単位の演算子も論理演算子です。
それにかんする
すでに論理演算子&&、||がありますが、なぜ&、|、^を使用するのですか?
XORは簡単に答えることができます。これはラジオボタンのようなもので、1つだけが許可され、以下のコードはfalseを返します。以下の考案されたコード例についてお詫びします。ビールとミルクの両方を同時に飲むのは悪いという信念はすでに明らかにされています;-)
String areYouDiabetic = "Yes";
String areYouEatingCarbohydrate = "Yes";
boolean isAllowed = areYouDiabetic == "Yes" ^ areYouEatingCarbohydrate == "Yes";
System.out.println("Allowed: " + isAllowed);
式の両側を評価する必要があるため、XORビット演算子に相当する短絡はありません。
論理演算子としてビット単位の演算子を使用する必要がある理由については、率直に言って&
、|
論理演算子としてビット単位の演算子(別名非短絡論理演算子)を使用する必要性を見つけるのは難しいでしょう。何らかの副作用を達成し、コードをコンパクト(主観的)にしたい場合は、論理演算を非短絡にすることができます(ビット演算子、別名非短絡論理演算子を使用)。
while ( !password.isValid() & (attempts++ < MAX_ATTEMPTS) ) {
// re-prompt
}
上記は次のように書き直すことができ(括弧を削除)、それでも前のコードとまったく同じ解釈になります。
while ( !password.isValid() & attempts++ < MAX_ATTEMPTS ) {
// re-prompt
}
括弧を削除しても、括弧で囲まれたものと同じ解釈が得られ、論理演算子の痕跡を&
より明確にすることができます。不必要に聞こえるリスクを冒すために、しかし私は括弧で囲まれていない表現がこれとして解釈されないことを強調しなければなりません:
while ( ( !password.isValid() & attempts++ ) < MAX_ATTEMPTS ) {
// re-prompt
}
要約すると、&
副作用を達成するために非短絡論理演算に演算子(より一般的にはビット演算子のみとして知られていますが、実際にはビット単位と論理(非短絡)の両方)を使用することは賢い(主観的)ですが、推奨されていませんが、読みやすさと引き換えに1行の節約効果にすぎません。
ここからの例:非短絡論理演算子が存在する理由
Java型のバイトは符号付きですが、これはビット演算子にとって問題になる可能性があります。負のバイトがintまたはlongに拡張されると、解釈された値を保持するために、符号ビットがすべての上位ビットにコピーされます。例えば:
byte b1=(byte)0xFB; // that is -5
byte b2=2;
int i = b1 | b2<<8;
System.out.println((int)b1); // This prints -5
System.out.println(i); // This prints -5
理由:(int)b1は内部的に0xFFFBであり、b2 << 8は0x0200であるため、iは0xFFFBになります
解決:
int i = (b1 & 0xFF) | (b2<<8 & 0xFF00);
System.out.println(i); // This prints 763 which is 0x2FB