[JAVA] 연산자
안녕하세요. 이번 글은 연산자에 대한 글입니다.
- 연산자란?
연산자는 우리가 배웠던 수학처럼 값을 상황에 알맞게 계산하기 위한 예약어를 의미한다.
자료형 | 연산 기호 | 우선 순위 |
증감 연산자 | ++, -- | 1 |
산술 연산자 | +, -, *, /, % | 2 |
쉬프트 연산자 | <<, >>, >>> | 3 |
비교 연산자 | >=, <=, ==, != | 4 |
논리 연산자 | &, &&, |, || | 5 |
삼항 연산자 | (조건) ? true : false | 6 |
대입 연산자 | =, +=, -=, /=, *=, %= ... | 7 |
연산자는 종류에 따라 크게 7가지로 분류된다. 우리가 사칙 연산을 배웠을 때도 괄호 안의 값부터 계산하고 곱하기나 나누기부터 먼저 계산하듯이 이 안에서도 우선순위가 존재한다. 이를 반영해서 우선순위대로 표를 제작하였다.
- 증감 연산자
증감 연산자는 말 그대로 증가 또는 감소시킬 수 있는 연산자이다. 여기서 크게 전위 연산자와 후위 연산자로 구분된다.
이 두 가지의 큰 차이점은 먼저 계산한 결과를 반영하고 안하고이다.
package classes;
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 10;
System.out.println(++a);
System.out.println(b++);
System.out.println(a + " " + b);
}
}
해당 이미지는 상단의 소스코드에 대한 실행결과이다.
a는 전위 연산자, b는 후위 연산자를 사용하였다. 이 둘의 결과 처음 출력문에서는 11과 10을 출력했고
그 다음 출력문에서는 두 변수 동일하게 11을 출력한 결과를 확인할 수 있다.
전위 연산자는 변수 앞에 ++ 또는 --를 붙이는데 이는 '먼저 값을 미리 계산해둔다.'는 뜻이다. 반면 후위 연산자는 변수 뒤에 ++ 또는 --를 붙이는데 이는 '값을 먼저 출력한 후 나중에 계산한다.'는 뜻이다.
또 다른 말로 하자면 전위 연산자는 연산 작업을 먼저 진행하고 코드에 해당 결과를 보여준다는 뜻이고 후위 연산자는 코드를 먼저 보여주고 연산 작업을 진행한다는 뜻이다. 이는 곧 '연산작업과 출력의 우선순위 차이'라고 볼 수 있다.
- 산술 연산자
산술 연산자는 '우리가 흔히 사용하는 사칙 연산'이라고 볼 수 있다.
package classes;
public class Main {
public static void main(String[] args) {
int a = 20;
int b = 15;
System.out.println(a + b);
System.out.println(a - b);
System.out.println(a * b);
System.out.println(a / b);
System.out.println(a % b);
}
}
해당 이미지는 상단 산술 연산자에 대한 소스 코드에 대한 실행 결과이다.
이들을 통해 +는 더하기, -는 빼기, *는 곱하기, /는 나누기라는 점을 확인할 수 있다.
추가로 %는 두 개의 값을 나눠서 나오는 나머지 값을 계산하는 연산자이다.
20에서 15를 나누면 몫은 1이고 나머지는 5이며 검산 (15 * 1) + 5 = 20을 통해 나머지 값이라는 점을 검증할 수 있다.
- 쉬프트 연산자
이는 비트(Bit)의 위치를 좌우로 이동하는 연산자를 의미한다.
package classes;
public class Main {
public static void main(String[] args) {
int a = 20;
int result = a << 1;
System.out.println(result);
}
}
여기서 '<<'을 통해 20이라는 2진수 내에서 맨 우측에서부터 1번 왼쪽으로 이동시켰다. 그리고 이를 2진수를 통해 확인할 수 있다. 20에서의 이진수는 00010100이다. 그러나 우측에서부터 1번 왼쪽으로 이동시켰다. 이동시킨만큼 비워져있을 공간은 0으로 채웠다. 물론 맨 앞에 밀려가는 비트값 또한 좌측으로 밀려나간다. 이후 결과는 00101000인데 이를 10진수로 변환하면 40이다. 소스코드에서도 결과값이 40으로 나오는 것을 확인할 수 있다.
이 처럼 << 또는 >>을 사용하면 해당 값의 이진수의 비트값이 좌측 또는 우측으로 n번씩 이동시킬 수 있으며 이동시키면서 10진수의 값 또한 달라진다는 점을 확인할 수 있다.
package classes;
public class Main {
public static void main(String[] args) {
int a = 20;
int result = a >> 1;
System.out.println(result);
}
}
이는 20에 대한 이진수를 기반으로 비트값을 1번 우측으로 이동시킨 소스코드이다. 그리고 이를 2진수를 통해 확인할 수 있다. 20에서의 이진수는 00010100이다. 이를 우측으로 한 번 이동시키면 0001010이다. 여기서 우측으로 이동하는데 맨 좌측 부호 비트값은 그대로 유지된 채 두 번째부터 빈 공간이 생긴다. 이때는 최상위 부호 비트로 채워진다. 양수이면 0, 음수이면 1로 채워진다는 의미이다.
이후 결과는 0001010인데 이를 10진수로 변환하면 10이다. 소스코드에서도 같은 결과값을 확인할 수 있다.
package classes;
public class Main {
public static void main(String[] args) {
int a = -20;
int result = a >>> 1;
System.out.println(result);
}
}
이는 -20에 대한 이진수를 기반으로 비트값을 1번 우측으로 이동시킨 소스코드이다. 그리고 이를 이진수를 통해 확인해볼 수 있다. 그러나, 아까 설명했던 >>와는 조금 다르게 볼 필요가 있다. 기존 >> 연산자는 부호 비트는 그대로 둔 채 두 번째 자리부터 이동하는 방식이었으나 >>> 논리 시프트 연산자는 부호 비트도 함께 이동하는 방식이다. 이 때 이동하면서 비워지는 칸들은 모두 0으로 채워진다. 그러므로 아무리 음수값이어도 >>> 연산자를 사용하면 무조건 양수로 바뀐다.
또한 음수를 논리 시프트 연산자를 사용하게 되면 양수로 전환될 뿐만 아니라 10진수로 재변환하는 과정에 매우 큰 수로 바뀌는 점을 확인할 수 있다.
- 비교 연산자
비교 연산자는 두 개의 숫자 및 문자를 비교 또는 대조하기 위한 연산자를 의미한다.
package classes;
public class Main {
public static void main(String[] args) {
System.out.println(10 == 10); // true
System.out.println(10 == 15); // false
System.out.println(10 != 60); // true
System.out.println(10 != 10); // false
System.out.println(10 > 9); // true
System.out.println(10 >= 10); // true
System.out.println(10 < 52); // true
System.out.println(10 <= 9); // false
}
}
비교 연산자에 대한 결과는 논리 자료형으로 true, false로 나온다.
먼저 '=='는 equal의 의미를 지님으로써 앞의 값과 뒤의 값이 같다는 뜻이다. 반면 '!="는 not equal의 뜻으로 두 수가 같지 않음을 의미한다.
'>'은 a > b라고 가정했을 때, a가 b보다 크다는 뜻이며 '<'은 a < b라는 상황 안에서 a는 b보다 작다는 뜻이다.
'>='은 a >= b라고 가정했을 때 a가 b보다 크거나 같다는 뜻이며 '<='은 a <= b는 a가 b보다 작거나 같다는 뜻이다.
- 논리 연산자
논리 연산자는 피연산자로 boolean 값만 사용할 수 있으며 연산에 대한 결과 또한 논리값으로만 도출되는 연산자이다.
package classes;
public class Main {
public static void main(String[] args) {
System.out.println(5 + 2 == 7 && 5 + 5 == 10); // true
System.out.println(5 + 2 == 7 && 5 + 5 == 15); // false
System.out.println(true || false); // true
System.out.println(false || false); // false
System.out.println(true ^ true); // false
System.out.println(true ^ false); // true
System.out.println(false ^ true); // true
System.out.println(false ^ false); // false
System.out.println(!true); // false
System.out.println(!false); // true
boolean t = ( (10 != 0) | (0 != 0) | (3 != 0) );
System.out.println(t); // true
boolean t2 = ( (10 != 0) & (0 != 0) & (1 + 2 >= 3) );
System.out.println("t2 : " + t2); // false
}
}
다음은 논리 연산자를 작동시킨 소스 코드이다. 여기서 논리 연산자 종류를 크게 &&, ||, ^, !, &, | 6가지를 확인할 수 있다.
먼저 &&는 AND를 의미한다. 이는 두 개 이상의 조건이 모두 참이어야 true가 출력된다는 뜻이다. 어느 하나라도 거짓이 나오면 false를 출력한다.
||는 OR를 의미한다. 이는 두 개 이상의 조건 중에서 하나라도 참이면 true를 출력한다. 수 많은 거짓들이 존재해도 단 하나의 참이 존재하면 최종적으로 true를 출력한다.
^는 XOR를 의미한다. 이는 조건의 결과가 참, 거짓 모두 상관없이 두 개의 조건이 모두 결과값을 보여주면 true를 보여주고 반면에 조건의 결과가 각각 다른 결과값을 보여주면 false를 보여준다.
!는 NOT를 의미한다. 이는 해당되는 논리결과에 대한 반대의 결과를 출력한다.
|과 &는 OR과 AND의 다른 버전이라고 볼 수 있다. 먼저 |는 ||과 똑같이 단 하나라도 참이면 모두 참이라고 간주하고 &는 &&과 똑같이 단 하나라도 거짓이면 모두 거짓이라고 간주한다.
차이점은 단 하나이다. 그것은 아무리 최종결과가 나왔더라도 주어진 조건에 대한 참 거짓 여부를 끝까지 검사하는 것이다.
- 삼항 연산자
삼항 연산자는 조건문 파트에서 배울 if-else문을 한 줄로 간단한 형식으로 구현하도록 하는 연산자이다.
package classes;
public class Main {
public static void main(String[] args) {
String result = (5+2==7) ? "OK" : "NO";
System.out.println(result);
}
}
상단의 소스코드를 보면 알 수 있다시피 삼항 연산자의 문법은 (조건) ? 참 : 거짓 이다.
package classes;
public class Main {
public static void main(String[] args) {
if (5 + 2 == 7) {
System.out.println("OK");
}
else {
System.out.println("NO");
}
}
}
조건문 if-else 문대로 사용하게 되면 길게 나온다는 점을 확인할 수 있다. 물론 이러한 조건 검사는 if-else문 같은 조건문을 더 많이 사용하겠지만 삼항 연산자는 상대적으로 간결하게 조건을 검사할 수 있다는 점이 특징이자 장점이라고 볼 수 있다.
- 대입 연산자
대입 연산자는 좌측 = 우측 처럼 우측에 있는 값을 좌측에 반영하겠다는 뜻을 지니는 연산자이다.
그 중에서도 대표적으로 =, +=, -=, /=, *=, %=가 있다.
package classes;
public class Main {
public static void main(String[] args) {
int a;
a = 10;
System.out.println(a);
a = 10;
System.out.println(a += 2); // a = a + 2
a = 10;
System.out.println(a -= 2); // a = a - 2
a = 10;
System.out.println(a /= 5); // a = a / 5
a = 10;
System.out.println(a *= 2); // a = a * 2
a = 10;
System.out.println(a %= 3); // a = a % 3
}
}
먼저 +=는 a = a + 2 처럼 앞의 변수에 2를 더한 값을 앞의 변수에다 대입하겠다는 뜻이다.
-=는 변수에 일정 값을 뺀 값을 /=는 나눈 값을 *=는 곱한 값을 %=는 나눠서 나온 나머지 값을 앞의 변수에다 대입한다는 의미이다. 상단 소스코드의 결과는 10, 12, 8, 2, 20, 1 이다.
이렇게 +=, -=, *=, /=, %=과 같이 계산식을 하나의 형식으로 간단히 요약한 연산자를 복합 대입 연산자라고 한다.