検索

キーワード


【Java】比較演算子、論理演算子、ビット演算子、シフト演算子の使い方について解説!

  • 公開日:2020-09-08 17:29:42
  • 最終更新日:2021-01-25 17:45:15
【Java】比較演算子、論理演算子、ビット演算子、シフト演算子の使い方について解説!

こんにちは。駆け出しプログラマーの松倉です!

ここでは、演算子の基本である比較演算子、論理演算子、ビット演算子、シフト演算子ついて紹介・解説します。

プログラミング未経験の方、Javaについて勉強している方、これから勉強したいと思っている方の参考になれば幸いです!

関連記事リンク:【Java】リテラルってなに? リテラル(数値、文字、文字列)の使い方を解説!【Java】変数とは?定数とは?詳しく解説! 変数の列挙型、代入、型変換、型推論の使い方についても紹介します!【Java】演算子(算術演算子と複合演算子)の使い方を解説! インクリメントとデクリメントの使い方!【Java】if文?switch文? 条件分岐の追加方法など使い方を解説!【Java】while文や for文などの反復処理(繰り返し構文)と breakや continueなどの反復制御の使い方!


演算子

値を使った計算のことを演算と呼びます。

+(プラス)や -(マイナス)などのプログラムで計算を行うための記号や、複数の値の比較を行うための記号など何らかの演算を行う記号を演算子(オペレーター)といいます。

演算の方法は演算子によって区別されます。


この記事では演算子について以下のことを紹介・解説を行います。

  • 比較演算子
  • 論理演算子
  • ビット演算子
  • シフト演算子


比較演算子

プログラムの処理を制御するため条件分岐や、繰り返し処理などが多く使用されます。

条件分岐のような制御構文と合わせて使用され、2つの式や値の比較を行います。

比較演算子は等しいかどうか、あるいは 2つの大小を調べる演算子です。

「<=」や「==」のような比較演算子を含む式が正しければ trueとなり、間違っていれば falseとなります。

Javaで以下の比較演算子が用意されています。

             Javaにおける比較演算子の一覧

「<、<=、>、>=」大小の比較をする場合に使用します

「==、!=」等しいかどうかの比較する場合に使用します。


比較演算子を使ったサンプルコードを確認しましょう。

public class Sample1 {
	public static void main(String args[]) {
		int a = 20;
		int b = 10;

		if (a > b) {
			System.out.println("aはbよりも大きい");
		} else if (a <= b) {
			System.out.println("aはbよりも小さいか等しい");
		}

		if (a == b) {
			System.out.println("aとbは等しい");
		} else if (a != b) {
			System.out.println("aとbは等しくない");
		}
	}
}


実行結果:

aはbよりも大きい
aとbは等しくない

比較演算子を条件分岐と組み合わせて使うことで変数 aと変数 bの大小や等しいかを判別できました。



論理演算子

論理演算子は真偽値同士の組み合わせを評価し、その結果を trueまたは falseで返す演算子です。

論理演算子は比較演算子と組み合わせえて使うことで様々な条件を記述することができます。

Javaは以下の論理演算子が用意されています。

             Javaにおける論理演算子の一覧

「&&、||」と「&、|」の違いは左式の結果のみで全体の実行結果が判別できる時、右式を実行するかどうかです。

「&&」演算子は左式が falseの場合、右式の値に関わらず式全体が falseとなります。

同様に「||」演算子は左式が trueの場合、右式の値に関わらず式全体が trueとなります。

右式が評価されずにスキップされるためショートカット演算と呼ばれます。


論理演算子を用いたサンプルコードを確認しましょう。

public class Sample2 {
	public static void main(String[] args) {
		int count1 = 0;
		System.out.println("AND演算.1:" + (true && ++count1 < 100));
		System.out.println("count1 = " + count1);

		int count2 = 0;
		System.out.println("AND演算.2:" + (false && ++count2 < 100));
		System.out.println("count2 = " + count2);

		int count3 = 0;
		System.out.println("OR演算.1:" + (true || ++count3 < 100));
		System.out.println("count3 = " + count3);

		int count4 = 0;
		System.out.println("OR演算.2:" + (false || ++count4 < 100));
		System.out.println("count4 = " + count4);

		System.out.println("NOT演算:" + !true);

		System.out.println("XOR演算:" + (true ^ true));
	}
}


実行結果:

AND演算.1true
count1 = 1
AND演算.2false
count2 = 0
OR演算.1true
count3 = 0
OR演算.2true
count4 = 1
NOT演算:false
XOR演算:false

「&&」や「||」のようなショートカット演算子を使用した場合、右式の結果に関わらず左式の結果だけで式全体が評価されることがあります。

Sample2の AND演算.1は左式が true、OR演算.2は左式が flaseのであり、左式の結果のみで全体の実行結果が判別できません。

そのため右式が実行され、countに 1が足されています。

一方でSample2の AND演算.2は左式が false、OR演算.1は左式が trueのであり、左式の結果のみで全体の実行結果が判別できると処理されます。

そのため右式の実行は行われず、countは元の値である 0のまま処理が終了しています。

これらのことから右式の結果に関わらず、左式の結果だけで式全体が評価されることが確認できました。


ショートカット演算を使わない場合、実行結果にどのような違いがあるのかサンプルコードで確認しましょう。

public class Sample3 {
	public static void main(String[] args) {
		int count1 = 0;
		System.out.println("AND演算.1:" + (true & ++count1 < 100));
		System.out.println("count1 = " + count1);

		int count2 = 0;
		System.out.println("AND演算.2:" + (false & ++count2 < 100));
		System.out.println("count2 = " + count2);

		int count3 = 0;
		System.out.println("OR演算.1:" + (true | ++count3 < 100));
		System.out.println("count3 = " + count3);

		int count4 = 0;
		System.out.println("OR演算.2:" + (false | ++count4 < 100));
		System.out.println("count4 = " + count4);
	}
}


実行結果:

AND演算.1true
count1 = 1
AND演算.2false
count2 = 1
OR演算.1true
count3 = 1
OR演算.2true
count4 = 1

Sample2の実行結果では左式で実行結果が判別できた場合、右式の処理が行われませんでした。

そのため右式が実行されたものと、実行されていないものがありました。

一方で、Sample3では左式の評価に関わらず右式の処理が実効され、いずれの場合でも countに 1足された結果が出力されました。

ショートカット演算を使う場合はこのような処理の違いがあります。

実際に使うときは左式の結果がある場合、右式の処理が必要かどうかを判断して使いましょう。



ビット演算子

整数の値に対してビット単位で処理を行うために用意されているのがビット演算子です。

コンピュータ内部では、すべての情報は電気信号の「ON」、「OFF」のように 2値で扱われています。

これを一般的に 2進数の「0」と「1」に対応して表現しています。

コンピュータで扱う最小の情報量の単位をビット(bit)といい、2進数の 1桁に相当します。

例えば、“ 10001111 ”は 8ビットの情報量であり、このような羅列をビットパターンと呼びます。

ビットの演算とは整数の数値を 2進数として見て各桁(bit)の 1を true、0を falseとみなし、bitごとに論理演算を行う計算方法です。

「元のビット列」と「特定のビット列(マスクパターン)」との間でビット演算を行い、ある特定のビットを取り出したり、反転させたりすることができます。

Javaでハードウェアを扱うときなどに重要になってきます。

Javaは以下のビット演算子が用意されています。

            Javaにおけるビット演算子の一覧

〇演算子「&」

2つスイッチを比較して、どちらも 1なら 1、どちらか片方でも 0の場合は 0を返します。

例:c = a & b

演算子「&」を使った演算の例

〇演算子「|」

2つスイッチを比較して、どちらかが 1なら 1、どちらも 0の場合は 0を返します。

例:c = a | b

演算子「|」を使った演算の例

〇演算子「^」

2つスイッチを比較して、どちか片方だけ 1なら 1、どちらも 0またはどちらも 1の場合は 0を返します。

例:c = a ^ b

演算子「^」を使った演算の例

〇演算子「~」

スイッチの ON/OFFの状態をすべて逆転させ、0は 1に、1は 0に変えます。

例:c = ~a

演算子「^」を使った演算の例


ビット演算子を使ったサンプルコードを確認しましょう。

public class Sample3 {
	public static void main(String args[]) {
		int a = 0b101101;//45
		int b = 0b011001;//25

		int and = a & b;
		System.out.println("0b101101 & 0b011001 = " + Integer.toBinaryString(and));

		int or = a | b;
		System.out.println("0b101101 | 0b011001 = " + Integer.toBinaryString(or));

		int xor = a ^ b;
		System.out.println("0b101101 ^ 0b011001 = " + Integer.toBinaryString(xor));

		int not = ~a;
		System.out.println("~0b101101 = " + Integer.toBinaryString(not));
	}
}


実行結果:

0b101101 & 0b011001 = 1001
0b101101 | 0b011001 = 111101
0b101101 ^ 0b011001 = 110100
~0b101101 = 11111111111111111111111111010010

変数 aと変数 bでビット演算が行われたことが確認できました。


※ NOT演算子の出力結果について解説します。

このサンプルコードでは Integerクラスの「toBinaryString」メソッドを使用しました。

このメソッドは整数引数の文字列表現を 2の符号なし整数として返し、引数が負の数の場合は引数に 2^32を加算した値になります。

そのため変数 aの 45は 32ビットで格納されるため

"0000 0000 0000 0000 0000 0000 0010 1110" と表現されます。

2進数ではマイナス表現は先頭 bitが「1」で処理しています。

45の NOT演算では全ての「0」と「1」が逆転するため、

45の補数である -46 は

"1111 1111 1111 1111 1111 1111 1101 0001" に "1" を足した

"1111 1111 1111 1111 1111 1111 1101 0010" と表現されます。

処理される値が何ビットで格納されるのかによって、返す値の桁数が変わるということです。

8ビットで格納される場合、-46は "1101 0010" と表現されます。



シフト演算子

ビット演算子で用意されている演算子の中にシフト演算子と呼ばれるものがあります。

シフト演算は 2ビットパターンを左右にずらすことで簡単に乗算や除算を行う演算です。

10進数で左右に桁をシフトした場合、それは元の数値を 10倍にしたり 1/10することを意味します。

例えば 1000を左に一つシフトすると 10000になり、1000を右に一つシフトすると 100になります。

同様に 2進数では左右に桁シフトした場合、元の数値に 2倍にしたり 1/2することができます。

Javaは以下のシフト演算子が用意されています。

            Javaにおけるシフト演算子の一覧

シフト演算子は整数型の値に使用されます。

〇演算子「<<

<<は左の値のビットを右の値のビット分だけ、左にシフトさせます。

左へのシフトは元の値に 2^nした値を乗算することを意味します。

2 << 3 

↓ 2 × 2 ^ 3 = 16

演算子「<<」を使った演算の例

〇演算子「>>

>>は左値のビットを右の値のビット分だけ、右にシフトさせます。

右へのシフトは元の値に 2^nした値を除算することを意味します。

左端には最上位のビットと同じ符号が入ります。

2進数での補数表現は負数の最上位ビットは 1であるため、最上位のビットと同じ符号でなければなりません。

-4 >> 2 

↓ -4 ÷ 2 ^ 2 = -1

演算子「>>」を使った演算の例

〇演算子「>>>

>>>は左の値のビットを右値のビット分だけ、右にシフトさせます。

左端には空いたビットの数だけ 0が入ります。

必ず 0が入るため>>>演算子は符号の区別を持たない演算処理に使用します。

64 >>> 3 

↓ 64 ÷ 2 ^ 3 = 8

演算子「>>>」を使った演算の例


シフト演算を使ったサンプルコードを確認しましょう。

public class Sample4 {
	public static void main(String args[]) {
		byte b;
		b = 4 << 3;
		System.out.println("4 << 3 = " + b);

		b = -8 >> 1;
		System.out.println("-8 >> 1 = " + b);

		b = 20 >>> 2;
		System.out.println("20 >>> 2 = " + b);
	}
}


実行結果:

4 << 3 = 32
-8 >> 1 = -4
20 >>> 2 = 5

元の値が指定された値だけシフト演算が行われたことが確認できました。


まとめ

今回の記事では基本的な演算子について紹介・解説しました。

プログラムを書く時には比較演算子は条件分岐のような制御構文でよく使われ、大概の場合これがないとプログラムが書けなくなるほどとても重要な演算子です。

比較演算子についてはしっかりと学習しましょう。

また比較演算子と論理演算子を組み合わせることで、より複雑で高度なプログラムを書くことができます。

論理演算子を使いこなすことができるとプログラムの可読性の向上につながるのでぜひ覚えましょう。

ビット演算子とシフト演算に関してですが、普段プログラムを書く時にはあまり使われることがない演算子だと思います。

実際に必要になったときこの記事を読み返しに来てくださいね。

何気なく使っている演算子ですが、使い方ひとつで様々なメリットがあるのでどんどん使ってみましょう!


関連記事リンク:【Java】リテラルってなに? リテラル(数値、文字、文字列)の使い方を解説!【Java】変数とは?定数とは?詳しく解説! 変数の列挙型、代入、型変換、型推論の使い方についても紹介します!【Java】演算子(算術演算子と複合演算子)の使い方を解説! インクリメントとデクリメントの使い方!【Java】if文?switch文? 条件分岐の追加方法など使い方を解説!【Java】while文や for文などの反復処理(繰り返し構文)と breakや continueなどの反復制御の使い方!

【著者】

松倉祥大

はじめまして。フォワードソフト株式会社の松倉です。
システムエンジニアとして働き始めたのが2020年4月です。経験や知識がない状態で入社した私は、フォワードソフトの教育研修で一からプログラミングの勉強をしました。教育研修を卒業後、Javaのプログラミングについて初学者向けの記事を共同で制作しています。
知識や経験はまだまだですが、これからいろんな職場で様々な経験しながら勉強していきたいと思っています。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様