Skip to content

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) 증감 연산자의 연산 순서

  • 증감 연산자는 피연산자의 어느 쪽에 위치하는가에 따라 연산의 순서가 달라진다.


  • 다음 예제는 증감 연산자의 연산 순서를 살펴보기 위한 예제이다.


int x = 10;
int y = x-- + 5 + --x;

System.out.println("x: " + x + ", y: " + y);

// x: 8, y: 23


  • 다음 그림은 위의 예제에서 수행되는 연산의 순서를 보여준다.


003


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을 반환한다.


004


  • 다음 그림은 비트 OR 연산자(|)의 동작을 나타낸다.
  • 이처럼 비트 OR 연산자는 대응되는 두 비트 중 하나라도 1이면 1을 반환하며, 두 비트가 모두 0일 때만 0을 반환한다.


005


  • 다음 그림은 비트 XOR 연산자(^)의 동작을 나타낸다.
  • 이처럼 비트 XOR 연산자는 대응되는 두 비트가 서로 다르면 1을 반환하고, 서로 같으면 0을 반환한다.


006


  • 다음 그림은 비트 NOT 연산자(~)의 동작을 나타낸다.
  • 이처럼 비트 NOT 연산자는 해당 비트가 1이면 0을 반환하고, 0이면 1을 반환한다.


007


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배씩 증가한다는 사실을 알 수 있다.


008


  • 또한, ③번 라인의 오른쪽 시프트 연산자(>>)는 지정한 수만큼 피연산자의 모든 비트를 전부 오른쪽으로 이동시킨다.
  • 이때 비트의 이동으로 새로 생기는 왼쪽 비트들은 양수일 경우에는 모두 0으로 채워지며, 음수일 경우에는 모두 1로 채워진다.
  • 따라서 부호는 변하지 않는다.
  • 실행 결과를 살펴보면, 모든 비트가 한 비트씩 오른쪽으로 이동할 때마다 그 값은 2배씩 감소한다는 사실을 알 수 있다.


009


  • ④번 라인의 오른쪽 시프트 연산자(>>>)는 부호 비트까지 포함하여 모든 비트를 전부 오른쪽으로 이동시킨다.
  • 이때 비트의 이동으로 새로 생기는 왼쪽 비트들은 언제나 0으로 채워진다.
  • 따라서 피연산자가 양수인 경우에는 부호 비트를 이동하지 않는 오른쪽 시프트 연산자(>>)와 같은 결과를 반환한다.


010


  • 하지만 피연산자가 음수인 경우에는 부호 비트까지도 이동하므로, 전혀 다른 결과가 반환된다.


  • 다음 그림은 1바이트의 경우일 때 연산 결과를 나타내며, 위의 예제에서는 총 4바이트일 경우의 연산 결과를 보여준다.


011


  • 따라서 이 시프트 연산자는 10진수의 연산보다는 2진수의 연산에서만 주로 사용된다.


7) 기타 연산자

(1) 삼항 연산자(Ternary Operator)

  • 삼항 연산자는 자바에서 유일하게 피연산자를 세 개나 가지는 조건 연산자이다.


  • 삼항 연산자의 문법은 다음과 같다.


조건식 ? 반환값1 : 반환값2


  • 물음표 앞의 조건식에 따라 결괏값이 참이면 반환값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 클래스또는인터페이스이름


  • 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)

  • 연산자의 우선순위는 수식 내에 여러 연산자가 함께 등장할 때, 어느 연산자가 먼저 처리될 것인가를 결정한다.


  • 다음 그림은 가장 높은 우선순위를 가지고 있는 괄호 연산자를 사용하여 연산자의 처리 순서를 변경하는 것을 보여준다.


001


  • 연산자의 결합 방향은 수식 내에 우선순위가 같은 연산자가 둘 이상 있을 때, 먼저 어느 연산을 수행할 것인가를 결정한다.


002



References