자바(JAVA) 연산자
자바의 연산자에 대해서 알아보겠습니다.
1. 연산자
다음은 자바 연산자의 종류와 우선순위 입니다.
종류 |
연산방향 |
연산자 |
우선순위 |
단항연산자 |
← |
++, --, +, ~, !, (형변환 캐스트 연산자) |
높음 |
산술연산자 |
→ |
*, /, % |
|
→ |
+, - |
||
→ |
<<, >>, >>> |
||
비교연산자 |
→ |
<, >, <=, >=, instanceof |
|
→ |
==, != |
||
논리연산자 |
→ |
& |
|
→ |
^ |
낮음 |
|
→ |
| |
||
→ |
&& |
||
→ |
|| |
||
삼항연산자 |
→ |
?: |
|
대입연산자 |
← |
=, *=, /=, %=, +=, -=, <<= |
|
>>=, >>>=, &=, ^=, != |
위의 표에서 같은 줄에 있는 연산자들은 우선순위가 같고, 이러한 경우 연산 방향에 의해서 연산 순서가 정해집니다.
2. 단항 연산자
2.1 증감연산자
단항연산자가 일반적으로 피연산자의 오른쪽에 위치하는 다르게, 증감연산자는 양쪽 모두 위치하는 것이 가능합니다. 또한 위치에 따라 연산결과가 달라질 수 있습니다.
++ : 피연산자의 값을 1 증가
-- : 피연산자의 값을 1 감소
기본형 중에서 boolean형을 제외한 나머지 모든 타입에 대해 사용이 가능하며 피연산자를 기준으로 왼쪽에 사용하는 전위형과 오른쪽에 사용하는 후위형이 있습니다.
public class JavaApp { public static void main(String[] args) { int i = 5; int j = 0; j = i++; System.out.println("j=i++; 실행 후, i=" + i +", j="+ j); i = 5; // 결과를 비교하기 위해, i와 j의 값을 다시 5와 0으로 변경 j = 0; j = ++i; System.out.println("j=++i; 실행 후, i=" + i +", j="+ j); } }
위의 코드를 실행하면 다음과 같은 결과를 확인할 수 있습니다.
j=i++; 실행 후, i=6, j=5
j=++i; 실행 후, i=6, j=6
전위형과 후위형의 결과가 다르다는 것을 알 수 있습니다.
전위형 : 변수(피연산자)의 값을 먼저 증가시킨 후 변수를 참조
후위형 : 변수(피연산자)를 먼저 참조한 후 값을 증가
※ ++i 와 i = i + 1 은 같은 결과를 갖지만 연산 속도는 ++i가 더 빠릅니다. 또한 ++i가 수식을 더 간단히 하고 컴파일 후의 바이트 코드의 명령도 더 짧습니다.
2.2 부호 연산자
피연산자의 부호를 변경하는데에 사용됩니다. 기본형 중에서 boolean형과 char형을 제외한 나머지 타입에 대해 사용할 수 있습니다.
사용시 각각 양수1, 음수1을 곱한 결과를 얻게 됩니다.
+, -
ex)
int i = -10;
i = +i;
i = -i;
2.3 비트전환 연산자
정수형과 char형에만 사용될 수 있으며, 피연산자를 2진수로 표현했을 때, 0은 1로 1은 0으로 바꿔줍니다.
~
ex)
byte b = 10;
System.out.println("b = " + b );
System.out.println("~b = " + ~b);
System.out.println("~b+1 = " + (~b+1));
위의 예처럼 양의 정수 b가 있을 때, b의 음의 정수를 얻으려면 ~b+1 을 하면 되는 것을 알 수 있습니다.
다음 표를 통해 -10을 2진수로 어떻게 표현하는지 확인해보겠습니다.
2진수 |
10진수 |
0 0 0 0 1 0 1 0 |
10 |
1 1 1 1 0 1 0 1 |
-11 |
1 1 1 1 0 1 0 1 0 0 0 0 0 0 0 1 |
-11 + 1 |
1 1 1 1 0 1 1 0 |
-10 |
※ byte, short, char형은 int형으로 변환된 후에 비트전환이 이루어집니다.
비트전환 연산자는 피연산자 타입이 int형보다 작으면 int형으로 변환한 다음 연산을 합니다.
따라서 비트전환 연산자의 연산결과를 저장하기 위해서는 int형 변수에 담거나 캐스트 연산자를 사용해야 합니다.
2.4 논리부정 연산자
boolean형에만 사용되는 연산자이며 true는 false로, false는 true로 변경해줍니다.
!
ex)
boolean result = false;
result = !result;
3. 산술 연산자
산술연산자에는 사칙연산자(+,-,*,/), 나머지연산자(%), 쉬프트연산자(<<,>>,>>>)가 있습니다.
모두 두개의 피연산자를 필요로하는 이항 연산자입니다.
※ 이항연산자는 피연산자의 크기가 4byte보다 작으면 int형으로 변환하고 피연산자의 타입을 일치시킨 다음 연산을 수행합니다.
3.1 사칙연산자
사칙연산에 사용되는 연산자입니다. 곱셈(*), 나눗셈(/), 나머지(%) 연산자가 덧셈(+), 뺄셈(-) 연산자보다 우선순위가 높습니다.
다음과 같은 특징을 가지고 있습니다.
- int형 보다 크기가 작은 자료형(byte, short, char)은 int형으로 형변환된 후 연산이 이루어진다.
ex) byte + short → int + int = int
- 두 피연산자의 자료형이 다를 경우 큰 자료형에 맞춰서 형변환 된 후 연산이 이루어진다.
ex) int + float → float + float = float
- 정수형간의 나눗셈에서 0으로 나누는 것은 금지되어 있다.
※ 피연산자가 정수형인 경우에 0으로 나누면 컴파일은 되지만 ArithmeticException이 발생합니다.
아래 예제를 통해 대문자, 소문자의 코드값 차이를 확인해보겠습니다.
public class JavaApp { public static void main(String[] args) { char lowerCase = 'a'; char upperCase = (char) (lowerCase - 32); System.out.println(upperCase); } }
실행하면 다음과 같은 결과를 확인할 수 있습니다.
A
ASCII 코드에서는 대문자가 소문자보다 우선순위가 높고 십진수로 32의 코드값 차이를 가지고 있습니다.
대문자에서 소문자로 변경하려면 대문자에서 32를 더하고, 소문자에서 대문자로 변경하려면 소문자에서 32를 빼면 됩니다.
다음으로 아래 예제를 통해 나눗셈 연산자의 특징을 확인해보겠습니다.
public class JavaApp { public static void main(String[] args) { float pi = 3.141592f; float shortPi = (int) (pi * 1000) / 1000f; System.out.println(shortPi); } }
실행하면 다음과 같은 결과를 확인할 수 있습니다.
3.141
int형간의 나눗셈(int/int)을 수행하면 결과가 float나 double이 아닌 int로 나옵니다. 또한 결과를 반올림하지 않고 버립니다.
위의 예제의경우 (pi * 1000)의 연산이 우선 이루어 지고 다음으로 int형으로의 형변환이 이루어집니다.
피연산자는 3141 / 1000f 의 형태가 되는데 int형 / float형 의 연산이므로 큰 자료형에 맞춰서 한번 더 형변환이 이루어집니다.
최종적으로 3141.0f / 1000f 의 형태로 연산이 이루어지고 3.141로 결과가 나타나게 됩니다.
3.2 나머지 연산자
왼쪽의 피연산자를 오른쪽 피연산자로 나눈 후 나머지 값을 돌려주는 연산자입니다.
boolean형을 제외하고 다른 모든 기본형에 사용할 수 있으며, 나눗셈과 마찬가지로 피연산자가 정수형인 경우 나누는 연산자로 0을 사용할 수 없습니다.
%
ex) int remain = 10 % 8;
3.3 쉬프트 연산자
정수형 변수에만 사용할 수 있는 연산자입니다. 피연산자를 2진수로 표현했을 때 각 자리를 오른쪽 또는 왼쪽으로 이동해주는 연산자입니다.
<< : 피연산자 x를 왼쪽으로 n 자리 이동한 경우 x * 2^n의 결과와 같다. (빈자리를 0으로 채움)
>> : 피연산자 x를 오른쪽으로 n 자리 이동한 경우 x / 2^n의 결과와 같다. (빈자리를 1로 채움)
>>> : 피연산자 x를 오른쪽으로 n 자리 이동. (부호 상관없이 빈자리를 항상 0으로 채움)
'<<' 연산자의 경우 피연산자의 부호에 상관없이 자리를 왼쪽으로 이동시키며 빈칸을 0으로 채우면 됩니다.
하지만 '>>' 연산자는 오른쪽으로 이동시키기 때문에 음수인 경우 부호 유지를 위해 빈칸을 1로 채웁니다.
반면에 '>>>' 연산자는 오른쪽으로 이동하며 부호에 상관없이 빈칸을 항상 0으로 채웁니다.
다음 표를 통해 쉬프트 연산을 확인해보겠습니다.
수식 |
자리이동 |
연산결과 |
|
2진수 |
10진수 |
||
8 >> 0 |
없음 |
00000000 00000000 00000000 00001000 |
8 |
8 >> 1 |
오른쪽으로 한 번 |
00000000 00000000 00000000 00000100 |
4 |
8 >> 2 |
오른쪽으로 두 번 |
00000000 00000000 00000000 00000010 |
2 |
-8 >> 0 |
없음 |
11111111 11111111 11111111 11111000 |
-8 |
-8 >> 1 |
오른쪽으로 한 번 |
11111111 11111111 11111111 11111100 |
-4 |
-8 >> 2 |
오른쪽으로 두 번 |
11111111 11111111 11111111 11111110 |
-2 |
수식 |
자리이동 |
연산결과 |
|
2진수 |
10진수 |
||
8 << 0 |
없음 |
00000000 00000000 00000000 00001000 |
8 |
8 << 1 |
왼쪽으로 한 번 |
00000000 00000000 00000000 00010000 |
16 |
8 << 2 |
왼쪽으로 두 번 |
00000000 00000000 00000000 00100000 |
32 |
-8 << 0 |
없음 |
11111111 11111111 11111111 11111000 |
-8 |
-8 << 1 |
왼쪽으로 한 번 |
11111111 11111111 11111111 11110000 |
-16 |
-8 << 2 |
왼쪽으로 두 번 |
11111111 11111111 11111111 11100000 |
-32 |
수식 |
자리이동 |
연산결과 |
|
2진수 |
10진수 |
||
8 >>> 0 |
없음 |
00000000 00000000 00000000 00001000 |
8 |
8 >>> 1 |
오른쪽으로 한 번 |
00000000 00000000 00000000 00000100 |
4 |
8 >>> 2 |
오른쪽으로 두 번 |
00000000 00000000 00000000 00000010 |
2 |
-8 >>> 0 |
없음 |
11111111 11111111 11111111 11111000 |
-8 |
-8 >>> 1 |
오른쪽으로 한 번 |
01111111 11111111 11111111 11111100 |
2147483644 |
-8 >>> 2 |
오른쪽으로 두 번 |
00111111 11111111 11111111 11111110 |
1073741822 |
※ 쉬프트 연산자 역시 int형보다 작은 자료형인 경우 int형으로 형변환을 하여 연산을 수행합니다. 그렇기 때문에 위의 표에서 8이 4byte(32bit)로 표현되었습니다.
곱셈이나 나눗셈 연산자를 사용해도 같은 결과를 얻을 수 있지만, 쉬프트 연산자가 제공되는 이유는 속도가 더 빠르기 때문입니다.
따라서 곱셉이나 나눗셈 연산이 주로 사용되고 빠른 실행속도를 필요로 하는 곳에 쉬프트 연산자를 사용하면 됩니다.
4. 비교 연산자
두 개의 변수 또는 리터럴을 비교하는데 사용되는 연산자입니다.
주로 조건문과 반복문의 조건식에 사용되며, 결과는 true / false로 return 됩니다.
비교하는 자료형이 서로 다를 경우 큰 자료형의 타입에 맞게 형변환을 하여 일치시킨 후 비교합니다.
4.1 대소비교연산자
두 개의 피연산자의 크기를 비교합니다.
8개 기본형에서 boolean을 제외한 나머지 7개 타입에 대해 사용아 가능하고 참조형에는 사용할 수 없습니다.
<, >, <=, >=
4.2 등가비교연산자
두 개의 피연산자에 저장된 있는 값의 같음, 다름을 비교하는 연산자이며 기본형과 참조형에 모두 사용이 가능합니다.
기본형의 경우 값을 기준으로 비교하고 참조형의 경우 객체의 주소값을 비교합니다.
※ 등가비교연산자는 기본형과 참조형을 함께 사용하여 비교할 수 없습니다. (서로 형변환이 되지 않기 때문)
==, !=
4.3 비트연산자
이진 비트 연산을 수행하는 연산자입니다.
기본형 중에서 실수형인 float, double을 제외한 다른 모든 타입에 대해 사용이 가능합니다.
| : OR 연산자. 피연산자 중 한 쪽의 값이 1이면 1을 결과값으로 얻는다. 그 외에는 0을 얻는다.
& : AND 연산자. 피연산자 양쪽이 모두 1이어야 1을 결과값으로 얻는다. 그 외에는 0을 얻는다.
^ : XOR 연산자. 피연산자 양쪽이 서로 다를 때만 1을 결과로 얻는다. 양쪽이 서로 같을 때는 0을 얻는다.
※ 비트 연산자는 덧셈연산자(+)보다 우선순위가 낮기 때문에 괄호를 사용해야 합니다.
5. 그 외의 연산자
5.1 논리 연산자
논리 연산자는 피연산자로 boolean형만 허용하며 조건문에서 반복문과 조건식간의 결합에 사용됩니다.
&& : AND 결합. 피연산자 양쪽 모두 true여야 결과값으로 true를 얻는다.
|| : OR 결합. 피연산자중 한 쪽만 true이면 결과값으로 true를 얻는다.
※ '&&' 연산자가 '||' 연산자보다 우선순위가 높으므로 한 조건식에 함께 사용될 경우 괄호를 사용해서 우선순위를 명확하게 해줘야 합니다.
비트 연산자 '|' 연산자와 '&' 연산자도 피연산자로 boolean형을 허용하므로 조건식간의 연결에 사용할 수 있지만,
논리 연산자 '||' 연산자와 '&&' 연산자와는 다르게 양쪽의 피연산자를 모두 검사합니다.
5.2 삼항 연산자
세개의 피연산자를 필요로합니다. 조건식, true 반환값, false 반환값 세가지가 삼항연산자의 피연산자입니다. 또한 삼항연산자는 if문으로 바꿔 쓸 수 있습니다.
다음과 같은 형태로 사용합니다.
(조건식) ? 식1 : 식2
ex) String result = (x > 0) ? "TRUE" : "FALSE";
5.3 대입 연산자
대입 연산자는 변수에 값 또는 수식의 결과를 저장하는데에 사용합니다.
대입 연산자 왼쪽에는 반드시 변수가 위치해야하고 오른쪽에는 리터럴이나 변수 또는 수식이 올 수 있습니다.
=
ex)
int i=0;
i = i+3;
또한 대입 연산자는 다른 연산자와 결합하여 'op='와 같은 방식으로 사용될 수 있습니다.
op= |
= |
i += 3; |
i = i + 3; |
i -= 3; |
i = i - 3; |
i *= 3; |
i = i * 3; |
i /= 3; |
i = i / 3; |
i *= 10 + j; |
i = i * (10 + j); |
이상으로 자바의 연산자에 대해서 알아봤습니다.
※ 참고 문헌
남궁성, 『Java의 정석 3rd Edition』, 도우출판(2016), Chapter 03 연산자