3. 연산자(Operator)
1. 키워드
- 연산자(Operator)
- 산술 연산자(Arithmetic Operator)
- 대입 연산자(Assignment Operator)
- 증감 연산자(Increment and Decrement Operators)
- 비교 연산자(Comparison Operator)
- 논리 연산자(Logical Operator)
- 비트 연산자(Bitwise Operator)
- 삼항 연산자(Ternary Operator)
instanceof
연산자
2. 연산자(Operator)
- 자바에서는 여러 종류의 연산을 수행하기 위한 다양한 연산자를 제공하고 있다.
- 자바에서 제공하는 대표적인 연산자는 다음과 같다.
1] 산술 연산자(Arithmetic Operator)
2] 대입 연산자(Assignment Operator)
3] 증감 연산자(Increment and Decrement Operators)
4] 비교 연산자(Comparison Operator)
5] 논리 연산자(Logical Operator)
6] 비트 연산자(Bitwise Operator)
7] 삼항 연산자(Ternary Operator)
8] instanceof
연산자
1) 산술 연산자(Arithmetic Operator)
- 산술 연산자는 사칙연산을 다루는 연산자로, 가장 기본적이면서도 가장 많이 사용되는 연산자 중 하나이다.
- 산술 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽이다.
산술 연산자 | 설명 |
---|---|
+ |
왼쪽의 피연산자에 오른쪽의 피연산자를 더함 |
- |
왼쪽의 피연산자에서 오른쪽의 피연산자를 뺌 |
* |
왼쪽의 피연산자에 오른쪽의 피연산자를 곱함 |
/ |
왼쪽의 피연산자를 오른쪽의 피연산자로 나눔 |
% |
왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 반환함 |
int num1 = 8, num2 = 4;
System.out.println("+ 연산자에 의한 결과: " + (num1 + num2));
System.out.println("- 연산자에 의한 결과: " + (num1 - num2));
System.out.println("* 연산자에 의한 결과: " + (num1 * num2));
System.out.println("/ 연산자에 의한 결과: " + (num1 / num2));
System.out.println("% 연산자에 의한 결과: " + (num1 % num2));
// + 연산자에 의한 결과: 12
// - 연산자에 의한 결과: 4
// * 연산자에 의한 결과: 32
// / 연산자에 의한 결과: 2
// % 연산자에 의한 결과: 0
2) 대입 연산자(Assignment Operator)
- 대입 연산자는 변수에 값을 대입할 때 사용하는 이항 연산자이며, 피연산자들의 결합 방향은 오른쪽에서 왼쪽이다.
- 또한, 자바에서는 대입 연산자와 다른 연산자를 결합하여 만든 다양한 복합 대입 연산자를 제공한다.
대입 연산자 | 설명 |
---|---|
= |
왼쪽의 피연산자에 오른쪽의 피연산자를 대입함 |
+= |
왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
-= |
왼쪽의 피연산자에서 오른쪽의 피연산자를 뺀 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
*= |
왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
/= |
왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
%= |
왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 왼쪽의 피연산자에 대입함 |
&= |
왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
|= |
왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
^= |
왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
<<= |
왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
>>= |
왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
>>>= |
왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함 |
int num1 = 7, num2 = 7, num3 = 7;
num1 = num1 - 3;
num2 -= 3;
num3 =-3;
System.out.println("- 연산자에 의한 결과: " + num1);
System.out.println("-= 연산자에 의한 결과: " + num2);
System.out.println("=- 연산자에 의한 결과: " + num3);
// - 연산자에 의한 결과: 4
// -= 연산자에 의한 결과: 4
// =- 연산자에 의한 결과: -3
Note
- 위의 예제에서
num3 =- 3
연산은 단순히-3
을 변수num3
에 대입하는 연산이 된다. - 이처럼 복합 대입 연산자에서 연산자의 순서는 매우 중요하다.
3) 증감 연산자(Increment and Decrement Operators)
- 증감 연산자는 피연산자를
1
씩 증가 혹은 감소시킬 때 사용하는 연산자이다. - 이 연산자는 피연산자가 단 하나뿐인 단항 연산자이다.
- 증감 연산자는 해당 연산자가 피연산자의 어느 쪽에 위치하는가에 따라 연산의 순서 및 결과가 달라진다.
증감 연산자 | 설명 |
---|---|
++x |
먼저 피연산자의 값을 1 증가시킨 후에 해당 연산을 진행함 |
x++ |
먼저 해당 연산을 수행하고 나서, 피연산자의 값을 1 증가시킴 |
--x |
먼저 피연산자의 값을 1 감소시킨 후에 해당 연산을 진행함 |
x-- |
먼저 해당 연산을 수행하고 나서, 피연산자의 값을 1 감소시킴 |
int num1 = 7, num2 = 7;
int result1, result2;
result1 = --num1 + 4;
result2 = num2-- + 4;
System.out.println(
"전위 감소 연산자에 의한 결과: " + result1 + ", 변수의 값: " + num1
);
System.out.println(
"후위 감소 연산자에 의한 결과: " + result2 + ", 변수의 값: " + num2
);
// 전위 감소 연산자에 의한 결과: 10, 변수의 값: 6
// 후위 감소 연산자에 의한 결과: 11, 변수의 값: 6
- 위의 예제에서 첫 번째 연산은 변수
num1
의 값을 먼저1
감소시킨 후에 나머지 연산을 수행한다. - 하지만 두 번째 연산에서는 먼저 모든 연산을 마친 후에 변수
num2
의 값을1
감소시킨다. - 따라서 변수
num2
의 감소 연산자는 전체 연산자에 어떠한 영향도 미치지 않는다.
(1) 증감 연산자의 연산 순서
- 증감 연산자는 피연산자의 어느 쪽에 위치하는가에 따라 연산의 순서가 달라진다.
- 다음 예제는 증감 연산자의 연산 순서를 살펴보기 위한 예제이다.
- 다음 그림은 위의 예제에서 수행되는 연산의 순서를 보여준다.
1] 첫 번째 감소 연산자는 피연산자의 뒤쪽에 위치하므로, 덧셈 연산이 먼저 수행된다.
2] 덧셈 연산이 수행된 후에 감소 연산이 수행된다. (x
의 값: 9
)
3] 두 번째 감소 연산자는 피연산자의 앞쪽에 위치하므로, 덧셈 연산보다 먼저 수행된다. (x
의 값: 8
)
4] 감소 연산이 수행된 후에 덧셈 연산이 수행된다.
5] 마지막으로 변수 y
에 결괏값의 대입 연산이 수행된다. (y
의 값: 23
)
4) 비교 연산자(Relational Operator)
- 비교 연산자는 피연산자 사이의 상대적인 크기를 판단하는 연산자이다.
- 비교 연산산자는 왼쪽의 피연산자와 오른쪽 피연산자를 비교하여, 어느 쪽이 더 큰지, 작은지, 또는 서로 같은지를 판단한다.
- 비교 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽이다.
비교 연산자 | 설명 |
---|---|
== |
왼쪽의 피연산자와 오른쪽의 피연산자가 같으면 참을 반환함 |
!= |
왼쪽의 피연산자와 오른쪽의 피연산자가 같지 않으면 참을 반환함 |
> |
왼쪽의 피연산자가 오른쪽의 피연산자보다 크면 참을 반환함 |
>= |
왼쪽의 피연산자가 오른쪽의 피연산자보다 크거나 같으면 참을 반환함 |
< |
왼쪽의 피연산자가 오른쪽의 피연산자보다 작으면 참을 반환함 |
<= |
왼쪽의 피연산자가 오른쪽의 피연산자보다 작거나 같으면 참을 반환함 |
- 다음 예제는 소문자
'a'
와 대문자'A'
를 비교 연산자로 비교하는 예제이다.
char ch1 = 'a', ch2 = 'A';
System.out.println("== 연산자에 의한 결과: " + (ch1 == ch2));
System.err.println("> 연산자에 의한 결과: " + (ch1 > ch2));
// == 연산자에 의한 결과: false
// > 연산자에 의한 결과: true
- 일반적으로 영문자
'A'
와'a'
중에서 더 큰 문자는'A'
일 거라고 생각하기 쉽다. - 하지만 아스키코드에서
'A'
는 10진수65
로 나타내며,'a'
는 10진수97
로 나타낸다. - 따라서 두 문자를 비교하면
'a'
가 더 크다는 결과가 나오게 되는 것이다. - 모든 영문 대문자의 아스키 코드 값은 모든 영문 소문자보다 작은 값을 가진다.
Note
- 아스키코드(ASCII)는 영문 대소문자를 사용하는 7비트의 문자 인코딩 방식이다.
- 아스키코드는 문자를 7비트로 표현하므로, 총 128개의 문자를 표현할 수 있다.
5) 논리 연산자(Logical Operator)
- 논리 연산자는 주어진 논리식을 판단하여, 참과 거짓을 결정하는 연산자이다.
- AND 연산과 OR 연산은 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽이다.
- NOT 연산자는 피연산자가 단 하나뿐인 단항 연산자이며, 피연산자의 결합 방향은 오른쪽에서 왼쪽이다.
논리 연산자 | 설명 |
---|---|
&& |
논리식이 모두 참이면 참을 반환함 (논리 AND 연산) |
|| |
논리식 중에서 하나라도 참이면 참을 반환함 (논리 OR 연산) |
! |
논리식의 결과가 참이면 거짓을, 거짓이면 참을 반환함 (논리 NOT 연산) |
char ch1 = 'b', ch2 = 'B';
boolean result1, result2;
result1 = (ch1 > 'a') && (ch1 < 'z');
result2 = (ch2 < 'A') || (ch2 < 'Z');
System.out.println("&& 연산자에 의한 결과: " + result1);
System.out.println("|| 연산자에 의한 결과: " + result2);
System.out.println("! 연산자에 의한 결과: " + !result2);
// && 연산자에 의한 결과: true
// || 연산자에 의한 결과: true
// ! 연산자에 의한 결과: false
- 위의 예제처럼 자바에서는
char
형 문자끼리도 그 크기를 서로 비교할 수 있다.
6) 비트 연산자(Bitwise Operator)
- 비트 연산자는 논리 연산자와 비슷하지만, 비트(bit) 단위로 논리 연산을 할 때 사용하는 연산이다.
- 또한, 비트 단위로 왼쪽이나 오른쪽으로 전체 비트를 이동하거나, 1의 보수를 만들 때도 사용된다.
비트 연산자 | 설명 |
---|---|
& |
대응되는 비트가 모두 1 이면 1 을 반환함 (비트 AND 연산) |
| |
대응되는 비트 중에서 하나라도 1 이면 1 을 반환함 (비트 OR 연산) |
^ |
대응되는 비트가 서로 다르면 1 을 반환함 (비트 XOR 연산) |
~ |
비트를 1 이면 0 으로, 0 이면 1 로 반전시킴 (비트 NOT 연산, 1의 보수) |
<< |
명시된 수만큼 비트들을 전부 왼쪽으로 이동시킴 (left shift 연산) |
>> |
부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴 (right shift 연산) |
>>> |
지정한 수만큼 비트를 전부 오른쪽으로 이동시키며, 새로운 비트는 전부 0 이 됨 |
- 다음 그림은 비트 AND 연산자(
&
)의 동작을 나타낸다. - 이처럼 비트 AND 연산자는 대응되는 두 비트가 모두
1
일 때만1
을 반환하며, 다른 경우는 모두0
을 반환한다.
- 다음 그림은 비트 OR 연산자(
|
)의 동작을 나타낸다. - 이처럼 비트 OR 연산자는 대응되는 두 비트 중 하나라도
1
이면1
을 반환하며, 두 비트가 모두0
일 때만0
을 반환한다.
- 다음 그림은 비트 XOR 연산자(
^
)의 동작을 나타낸다. - 이처럼 비트 XOR 연산자는 대응되는 두 비트가 서로 다르면
1
을 반환하고, 서로 같으면0
을 반환한다.
- 다음 그림은 비트 NOT 연산자(
~
)의 동작을 나타낸다. - 이처럼 비트 NOT 연산자는 해당 비트가
1
이면0
을 반환하고,0
이면1
을 반환한다.
int num1 = 8, num2 = -8;
① System.out.println("~ 연산자에 의한 결과: " + ~num1);
② System.out.println("<< 연산자에 의한 결과: " + (num1 << 2));
③ System.out.println(">> 연산자에 의한 결과: " + (num2 >> 2));
④ System.out.println(">>> 연산자에 의한 결과: " + (num1 >>> 2));
⑤ System.out.println(">>> 연산자에 의한 결과: " + (num2 >>> 2));
// ~ 연산자에 의한 결과: -9
// << 연산자에 의한 결과: 32
// >> 연산자에 의한 결과: -2
// >>> 연산자에 의한 결과: 2
// >>> 연산자에 의한 결과: 1073741822
- 위 예제의 ①번 라인에서 비트 반전 연산자(
~
)는 피연산자의 1의 보수를 반환하므로, \(-(x+1)\)을 반환하게 된다. - ②번 라인의 왼쪽 시프트 연산자(
<<
)는 지정한 수만큼 피연산자의 모든 비트를 전부 왼쪽으로 이동시킨다. - 이때 비트의 이동으로 새로 생기는 오른쪽 비트들은 언제나
0
으로 채워진다. - 실행 결과를 살펴보면, 모든 비트가 한 비트씩 왼쪽으로 이동할 때마다 그 값은 2배씩 증가한다는 사실을 알 수 있다.
- 또한, ③번 라인의 오른쪽 시프트 연산자(
>>
)는 지정한 수만큼 피연산자의 모든 비트를 전부 오른쪽으로 이동시킨다. - 이때 비트의 이동으로 새로 생기는 왼쪽 비트들은 양수일 경우에는 모두
0
으로 채워지며, 음수일 경우에는 모두1
로 채워진다. - 따라서 부호는 변하지 않는다.
- 실행 결과를 살펴보면, 모든 비트가 한 비트씩 오른쪽으로 이동할 때마다 그 값은 2배씩 감소한다는 사실을 알 수 있다.
- ④번 라인의 오른쪽 시프트 연산자(
>>>
)는 부호 비트까지 포함하여 모든 비트를 전부 오른쪽으로 이동시킨다. - 이때 비트의 이동으로 새로 생기는 왼쪽 비트들은 언제나
0
으로 채워진다. - 따라서 피연산자가 양수인 경우에는 부호 비트를 이동하지 않는 오른쪽 시프트 연산자(
>>
)와 같은 결과를 반환한다.
- 하지만 피연산자가 음수인 경우에는 부호 비트까지도 이동하므로, 전혀 다른 결과가 반환된다.
- 다음 그림은 1바이트의 경우일 때 연산 결과를 나타내며, 위의 예제에서는 총 4바이트일 경우의 연산 결과를 보여준다.
- 따라서 이 시프트 연산자는 10진수의 연산보다는 2진수의 연산에서만 주로 사용된다.
7) 기타 연산자
(1) 삼항 연산자(Ternary Operator)
- 삼항 연산자는 자바에서 유일하게 피연산자를 세 개나 가지는 조건 연산자이다.
- 삼항 연산자의 문법은 다음과 같다.
- 물음표 앞의 조건식에 따라 결괏값이 참이면 반환값1을 반환하고, 결괏값이 거짓이면 반환값2를 반환한다.
int num1 = 5, num2 = 7;
int result;
result = (num1 - num2 > 0) ? num1 : num2;
System.out.println("두 정수 중 더 큰 수는 " + result + "입니다.");
// 두 정수 중 더 큰 수는 7입니다.
(2) instanceof
연산자
instanceof
연산자는 참조 변수가 참조하고 있는 인스턴의 실제 타입을 반환한다.- 즉, 해당 객체가 어떤 클래스나 인터페이스로부터 생성되었는지를 판별해 주는 역할을 한다.
instanceof
연산자의 문법은 다음과 같다.
instanceof
연산자는 왼쪽 피연산자인 인스턴스가 오른쪽 피연산자인 클래스나 인터페이스로부터 생성되었으면true
를 반환하고, 그렇지 않으면false
를 반환한다.
class A {}
class B extends A {
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println(a instanceof A); // true
System.out.println(b instanceof A); // true
System.out.println(a instanceof B); // false
System.out.println(b instanceof B); // true
}
}
2. 연산자의 우선순위(Operator Precedence)와 결합 방향(Associativity)
- 연산자의 우선순위는 수식 내에 여러 연산자가 함께 등장할 때, 어느 연산자가 먼저 처리될 것인가를 결정한다.
- 다음 그림은 가장 높은 우선순위를 가지고 있는 괄호 연산자를 사용하여 연산자의 처리 순서를 변경하는 것을 보여준다.
- 연산자의 결합 방향은 수식 내에 우선순위가 같은 연산자가 둘 이상 있을 때, 먼저 어느 연산을 수행할 것인가를 결정한다.