안녕하세요, 여행벌입니다.

오늘은 자바 연산자 중 이항 연산자들에 대해서 다뤄보겠습니다.


자바 연산자 종류


연산기호

결합 방향

우선순위 ( 낮을수록 높음 )

[ ], ( ), .

expr++, expr--

2

++expr, --expr, +expr, -expr, ~, !, (type), new

3

*, /, %

4

+, -

5

<<, >>, >>>

6

<, >, <=, >=, instanceof

7

==, !=

8

&

9

^

10

|

11

&&

12

||

13

? expr : expr

14

=, +=, -=, *=, /=, %=, ^=, |=, <<=, >>=, >>>=

15


이항 연산자


 피연산자가 둘인 연산자를 가리켜 '이항 연산자(binray operator)' 라 합니다. 피연산자는 데이터 그 자체를 대표함과 동시에 조작, 연산에 사용할 데이터를 지정하는 컴퓨터 명령의 일부입니다.


대입 연산자와 산술 연산자 : =, +, -, *, /, %


연산자 연산자의 기능 결합 방향
=

연산자 오른쪽에 있는 값을 연산자 왼쪽에 있는 변수에 대입.

a = 5;

+

두 연산자의 값을 더한다.

a = 4 + 3;

-

왼쪽의 피연산자 값에서 오른쪽의 피연산자 값을 뺀다.

a = 4 - 3;

*

두 피연산자의 값을 곱한다.

a = 4 * 3;

 

/

왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눈 몫을 반환한다.

a = 4 / 3;

%

왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눴을 때

얻게 되는 나머지를 반환한다.

a = 4 % 3;

 


복합 대입 연산자 : +=, -=, *=, /=, %=, &=, ^=, <<=, >>=, >>>=


연산자 연산자의 기능
+= a += b 는 a = a + b; 와 같습니다
-= a -= b 는 a = a - b; 와 같습니다.
*= a *= b 는 a = a * b; 와 같습니다.
/= a /= b 는 a = a / b; 와 같습니다.
%= a %= b 는 a = a % b; 와 같습니다.
&= a &= b 는 a = a & b; 와 같습니다.
^= a ^= b 는 a = a ^ b; 와 같습니다.
<<= a <<<= b 는 a = a << b; 와 같습니다.
>>= a >>= b 는 a = a >> b; 와 같습니다.
>>>= a >>>= b 는 a = a >>> b; 와 같습니다.

관계 연산자 : <, >, <=, >=, ==, !=


 관계 연산자는 두 개의 피연산자 사이에서 크기 및 동등 관계를 따져주는 이항 연산자로 결과에 따라서 true 또는 false를 반환합니다.

연산자 연산자의 기능 결합 방향
<

a < b

a 가 b 보다 작은가?

>

a > b

a 가 b 보다 큰가?

<=

a <= b

a 가 b 보다 작거나 같은가

>=

a >= b

a 가 b 보다 크거나 같은가

==

a == b

a 가 b 랑 같은가?

!=

a != b

a 가 b랑 다른가?


논리 연산자 : &&, ||, !


연산자 연산자의 기능 결합 방향
&&

A && B

A와 B 모두가 true이면 true, 아니면 false ( 논리 AND 와 동일 )

||

A || B

A와 B 모두가 false이면 false, 아니면 true ( 논리 OR 과 동일 )

!

!A

A가 true이면 false, false이면 true 반환 ( 논리 NOT )


예시 1)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int num1 = 0;
		int num2 = 0;
		boolean result;
		
		result = ((num1 += 10) < 0) && ((num2 += 10) > 0);
		System.out.println(result);
		System.out.println(num1);
		System.out.println(num2);
	}
}

 위의 출력 결과는 어떻게 될까요?

false
10
0

 num1은 10이지만, num2는 0인 것을 확인할 수 있습니다. 그 이유는 && 연산자 때문입니다. ( (num1 += 10) < 0 ) 이 먼저 수행되는데, num1 += 10을 하면 num1은 10이 되므로 0보다 작지 않습니다. 따라서 ( (num1 += 10) < 0 ) 은 false가 됩니다. 이때, && 연산자는 false가 하나라도 존재하면 어차피 false 값을 같습니다. 따라서 ( (num2 += 10) > 0) 연산을 진행하지 않고 result 에는 false가 저장됩니다. 


예시 2)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 5; // 코드 1번
		System.out.println(a++); // 코드 2번
		System.out.println(a); // 코드 3번
		System.out.println((a++ + 5) * 3); // 코드 4번
		a = (a++ + 5) * 3; // 코드 5번
		System.out.println(a); // 코드 6번
	}
}

 위의 코드는 어떤 값들을 출력할까요? 정답은 아래와 같습니다!

5
6
33
36

 코드 1번에서 a 에 5를 할당합니다.

 코드 2번에서는 a를 출력한 후, ++ 연산이 진행되므로 '5'를 출력하지만 a의 값은 6이 됩니다.

 코드 3번은 코드 2번에 의해 '6' 을 출력하게 됩니다.

 코드 4번에는 ( ) , ++, +, * 4가지 연산이 등장합니다. 우선순위는 ( ), ++, *, + 순으로 괄호 안에 식을 먼저 진행해야 됩니다. 따라서 ++ 과 + 연산이 진행되는데 이때, ++ 연산은 명령을 마무리 한 후에 a의 값을 올려주므로 (6 + 5) 가 진행됩니다. 그 후 * 3을 해서 33이라는 값이 만들어지고 a는 1 증가해서 7이 됩니다. 

 코드 5번은 ( ), ++, +, * , = 5가지 연산이 등장합니다. 우선순위는 ( ), ++, *, +, = 순으로 코드 4번과 마찬가지로 괄호 안에 식을 먼저 진행해야됩니다. 따라서 (7 + 5) 가 먼저 계산되고, 12 * 3이 계산되고 ++ 연산에 의해 a는 1 증가해서 8이 됩니다. 하지만 = 연산에 의해 계산된 36이란 값이 a에 저장되므로 a는 결국 36이 저장됩니다.


예시 3)


package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 1; // 코드1
		a = ~a; // 코드2
		System.out.println(a); // 코드3
	}
}

 위의 예시는 어떤 값을 출력할까요?

-2

 정답은 '-2' 입니다.

 컴퓨터는 모든 숫자를 2진수로 저장합니다. 우리는 앞의 포스팅에서 int 는 4바이트로 이루어져 있다고 배웠습니다. 따라서, a에 1을 할당하면 다음과 같이 컴퓨터에는 저장됩니다.

 a = 0000 0000 0000 0000 0000 0000 0000 0001 (2)

 ~ 연산은 쉽게 말하면 2진수로 저장된 a의 비트들을 반대로 바꿔주는 연산입니다. 즉, 코드2에 의해 a는 다음과 같이 바뀝니다.

 a = 1111 1111 1111 1111 1111 1111 1111 1110 (2)

 컴퓨터가 정수는 저장하는 방법인 2의 보수법에 의하면 위의 2진수 코드는 '-2' 를 의미합니다. 따라서 -2가 출력됩니다.


예시 4) 비트 연산자


 << 연산자는 비트 값들을 왼쪽으로 이동시킨 후에 오른쪽의 빈 공간에는 모두 0으로 채운다.

 >> 연산자는 비트 값들을 오른쪽으로 이동시킨 후에 왼쪽의 빈 공간에 양수라면 0으로, 음수라면 1로 채워줍니다.

 >>> 연산자는 비트 값들을 오른쪽으로 이동시킨 후에 부호와 상관없이 0으로 채워줍니다.

package Hello;

public class HelloWorld {
	public static void main(String args[]) {
		int a = 1; // 코드1
		a = a << 5; // 코드2
		System.out.println(a);
		a = a >> 3; // 코드3
		System.out.println(a);
		
		int b = -2147483648; // 코드4
		b = b >> 1; // 코드5
		System.out.println(b);
		
		int c = -2147483648; // 코드6
		c = c >>> 1; // 코드7
		System.out.println(c);
	}
}

 위의 예시는 어떤 값들을 출력할까요?

32
4
-1073741824
1073741824

 코드1에서 a에 1을 할당하므로 a = 0000 0000 0000 0000 0000 0000 0000 0001 (2) 가 됩니다.

 코드2에 의해 a는 왼쪽으로 5칸씩 비트가 이동하게 되고, 오른쪽의 파란 부분에는 0이 채워지고 위의 노란 부분에 해당하는 비트들은 사라지게 됩니다. 

 a = 0000 0000 0000 0000 0000 0000 0010 0000 (2)

 따라서, 현재 a는 10진법으로 32를 나타냅니다.

 코드3에 의해 a는 오른쪽으로 3칸씩 비트가 이동하게 되고, 양수이므로 왼쪽의 빨간 부분에 0이 채워지게 됩니다.

 a = 0000 0000 0000 0000 0000 0000 0000 0100 (2)

 따라서, 현재 a는 10진법으로 4를 나타냅니다.

 코드4에서 b에 -2147483648 을 할당하므로 b = 1000 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다.

 코드5에서 >> 연산은 음수 값은 왼쪽의 비는 부분을 1로 채우므로 b = 1100 0000 0000 0000 0000 0000 0000 0000(2) 가 되고, 10진수로 표현하면 -1073741824 가 됩니다.

 코드6에서 c = 1000 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다.

 코드7에서 >>> 연산은 부호에 상관 없이 왼쪽의 비는 부분을 0으로 채우므로 c = 0100 0000 0000 0000 0000 0000 0000 0000(2) 가 됩니다. 부호를 나타내는 맨 앞 코드가 0이 되어서 c는 양수가 되고 10진수로 표현하면 1073741824가 됩니다.

 

 비트 연산자는 따로 다른 포스팅에서 자세히 다뤄보겠습니다.


 

+ Recent posts