Dico

[Java] 연산자

구조

피연산자 연산자 피연산자

피연산자 Operand

연산자의 작업 대상

연산자 Operator

연산을 수행하는 기호.

피연산자로 연산을 수행하고 나면 항상 결과값을 반환한다.

결과값은 저장 공간에 저장하지 않으면 사라지기 때문에 결과를 얻는 것을 식을 평가(Evaluation)한다고 한다.

따라서 연산자와 피연산자가 조합된 것을 식(Expression)이라 한다.

대입 연산자와 증감 연산자만 피연산자의 값을 변경한다.

분류

비슷한 기능 :  산술, 비교, 논리, 대입

피연산자의 개수 :  단항(1개), 이항(2개), 삼항(3개)

우선 순위

식에 사용된 연산자가 둘 이상인 경우 처리하는 순서.

연산자의 우선 순위에 의해서 연산 순서가 결정된다.

우선 순위가 확실하지 않을 때는 괄호로 우선 순위를 임의로 높인다.

  • 단항 연산자   >   이항 연산자
  • 곱셈, 나눗셈   >   덧셈, 뺄셈
  • 산술 연산자   >   비교 연산자  >  논리 연산자
  •  논리 연산자 &&   >   논리 연산자 ||
  • 대입 연산자를 제외한 모든 연산자   >   대입 연산자

결합 규칙

하나의 식에 같은 우선 순위의 연산자들이 여러 개 있을 경우 처리하는 순서.

단항 연산자와 대입 연산자를 제외한 모든 연산자의 진행 방향은 왼쪽에서 오른쪽이다.

종류연산자결합 규칙우선 순위
단항 연산자++    --    +    -    ~    !    (type)높음
산술 연산자+    -    *    /    %    «    »
비교 연산자>    <    >=    <=    ==    !=    instanceof
논리 연산자&&    ||    &    |    ^ 
삼항 연산자?:
대입 연산자=    +=    -=    *=    /=    %=    «=    »=    &=    ^=    |=
낮음

산술 변환

서로 다른 타입의 피연산자를 연산할 경우 형변환 연산자로 값의 범위가 더 넓은 타입으로 타입을 일치시켜야 한다.

피연산자의 타입이 int보다 작으면 int로 변환한다.

쉬프트 연산자(<<, >>)와 증감 연산자(++, - -)는 예외이다.

long + intlong + long
byte + byteint + int

단항 연산자

증감 연산자

값을 1 증가/감소시킨다.

연산자표현의미예시
증가 연산자++피연산자의 값을 1 증가++i  ,  i++
감소 연산자--피연산자의 값을 1 감소--i  ,  i--

독립적인 하나의 문장으로 쓰이는 경우 연사자의 위치를 어디에 두던 상관 없지만

수식에 포함되거나 메서드의 매개변수로 사용된 경우 피연산자의 어느 쪽에 위치하냐에 따라 결과가 다르다.

식에 두 번 이상 포함된 변수에 사용하는 것은 피한다.

  • 전위형(Prefix)   : 피연산자의 왼쪽에 위치. 값이 참조되기 전에 증가/감소.
  • 후위형(Postfix) : 피연산자의 오른쪽에 위치. 값이 참조된 후에 증가/감소.
int a = 2;
a++;       // or ++a;
System.out.println(a + "");                       // 3

// 전위형
int d = 2, e = 0;
e = ++d;
System.out.println("d = " + d + ", e = " + e);    // d = 3, e = 3  : d+1 후 e가 참조함

// 후위형
int b = 2, c = 0;
c = b++;
System.out.println("b = " + b + ", c = " + c);    // b = 3, c = 2  : c가 b 참조 후 b+1
int a = 1, b = 2;
int result = ++a + --b + a--;
        // =  2  +  1  +  2 ;
        // =  5
System.out.println("a = " + a + ", b = " + b);    // a = 1, b = 1

증감 연산자가 산술 연산자보다 우선 순위가 높으므로 증감 연산 후 식을 계산한다.

부호 연산자

피연산자가 음수면 양수, 양수면 음수로 부호를 반대로 변경한 결과를 반환한다.

boolean과 char형을 제외한 기본형에만 사용할 수 있다.

int a = -2;
System.out.println(-a);   // 2

산술 연산자

사칙 연산자

+-*/
덧셈뺄셈곱셈나눗셈

int 보다 작은 타입끼리의 연산은 int로 변환 후 연산된다.

byte a = 10, b = 50;

byte c = a * b;              // error
byte d = (byte) (a * b);     // d = -12 (변환 타입 값의 범위 < 연산 결과 : 값 손실)
int e = a * b;               // e = 500

연산 결과가 반환 타입보다 크면 올바른 값을 얻을 수 없다.

int a = 100000;
long result = a * a;	    // 1410065408
  • 나눗셈과 곱셈

     정수형간의 나눗셈은 정수만 남고 나머지 값은 버려진다. 이때 반올림은 일어나지 않는다.

     올바른 값이 필요한 경우, 한 쪽을 실수형으로 형변환 시킨 후 연산한다.

int a = 5, b = 2;
int result = a / b;          // 2
float f = a / (float) b;     // f = 2.5

     피연산자가 정수형인 경우 나누는 수로 0을 사용할 수 없다.

     부동 소수점 값인 0.0f, 0.0d로 나누면 infinity(무한대)가 반환된다.

     같은 의미의 식이라도 연산의 순서에 따라서 다른 결과가 나올 수 있다.

int a = 100000;
int result1 = a / a * a;     // 100000
int result2 = a * a / a;     // 14100 : 먼저 곱하여 오버플로우 발생
  • 문자

     문자간의 사칙 연산은 정수간의 연산과 동일하다.

     0~9, A~Z, a-z까지 연속적으로 배치되어 있기 때문에 각 구간에서 그 구간의 첫 문자를 빼면 숫자로 변환된다.

int a = 'c' - 'a';    // 99 - 97 = 2
int b = '5' - '0';    // 53 - 48 = 5
int c = 'Z' - 'A';    // 90 - 65 = 25

     a 와 A의 차이가 32라는 점을 이용해 소문자를 대문자로, 대문자를 소문자로 바꿀 수 있다.

char a = (char) ('A' + 32);    // a
char A = (char) ('a' - 32);    // A
  • 문자형 변수와 정수 간의 사칙 연산 결과는 정수다.

     수식에 들어가 있는 변수는 컴파일러가 미리 계산할 수 없기 때문에 형변환을 해주어야 한다.

char c = 'a';
char c1 = c + 1;    // error
int i = c + 1;      // 98
  • 문자형 리터럴과 정수간의 사칙 연산 결과는 문자와 정수 둘 다 나올 수 있다.

     컴파일러가 미리 계산하여 타입에 맞게 저장하기 때문에 실행 시에는 연산이 수행되지 않는다.

char c1 = 'a' + 1;     // b
int i = 'a' + 1;       // 98

나머지 연산자 %

왼쪽의 피연산자(정수)를 오른쪽의 피연산자(0을 제외한 정수)로 나눈 후 나머지 값을 반환한다.

홀수, 짝수 또는 배수 검사 등에 주로 사용된다.

int x = 3;
int count = 0;
 
for (int i = 1; i < 20; i++) {
   if (i % x == 0) count++;    // 3의 배수. count = 6
} 

비교 연산자

조건문과 반복문의 조건식에서 두 피연산자를 비교하는 데 사용된다.

연산결과는 true와 false 중 하나가 나온다.

타입이 서로 다를 경우 값의 범위가 큰 쪽으로 자동 형변환하여 타입을 일치시킨 후 연산된다.

두 개의 기호로 이루어진 연산자는 기호의 순서를 바꾸거나, 중간에 공백이 들어가서는 안 된다. (>= → => or > =)

대소비교 연산자

두 피연산자의 값의 크기를 비교한다.

boolean과 참조형에는 사용할 수 없다.

  • >   :  좌변 값이 크면 true, 아니면 false
  • <   :  좌변 값이 작으면 true, 아니면 false
  • >=  :  좌변 값이 크거나 같으면 true, 아니면 false
  • <=  :  좌변 값이 작거나 같으면 true, 아니면 false

등가비교 연산자

두 피연산자의 값이 같은 지 또는 다른지를 비교한다.

모든 자료형에 사용할 수 있다.

  • 기본형 : 변수에 저장되어 있는 값이 같은 지 알 수 있다.
  • 참조형 : 두 피연산자가 같은 객체를 가리키고 있는 지 알 수 있다.
  • 기본형과 참조형 : 서로 형변환이 불가능하므로 비교할 수 없다.
  • ==  :  두 값이 같으면 true, 다르면 false
  • !=   :  두 값이 다르면 true, 같으면 false

문자열

두 문자열의 내용이 같은지 비교할 때는 equals()라는 메서드를 사용해야 한다.

대소문자를 구별하지 않고 비교하고 싶으면 equalslgnoreCase()를 사용한다.

String str = "a";
boolean p = str.equals("a");   // true

논리 연산자

둘 이상의 조건을 '그리고(and)'나 '또는(or)'으로 연결하여 하나의 식으로 표현할 수 있게 해준다.

논리 연산자

&&그리고피연산자 모두 참이어야 true
||또는피연산자 중 하나만 참이어도 true
!부정true는 false로, false는 true로 변경
  • 피연산자가 참인 경우와 거짓인 경우의 연산 결과
xyx&&yx||Y!x
truetruetruetruefalse
truefalsefalsetruefalse
falsefalsefalsefalsetrue
falsetruefalsetruetrue
  • &&와 ||이 같이 있을 때 &&가 먼저 평가된다.

     따라서 한 조건식에 &&와 ||을 함께 사용할 경우 괄호로 우선 순위를 명확히 표시한다.

if ((a < 5 || a == 4) && a != 1) ;
    • 논리 부정 연산자 !

         논리형에만 사용할 수 있다.

         반복적으로 적용하면 참과 거짓이 차례대로 반복되는 원리를 이용해 토글 버튼을 논리적으로 구현할 수 있다.

    boolean flag = true;
    flag = !flag;        // false
    flag = !flag;        // true 
    flag = !flag;        // false 
      • 효율적인 연산

           && : 왼쪽 피연산자가 false면 오른쪽 피연산자는 값을 평가하지 않는다.

           || : 왼쪽 피연산자가 true면 오른쪽 피연산자는 값을 평가하지 않는다.

      int a = 2, b = 0;
      System.out.println((a < 3 || ++b != 0) + ", " + b);    // true, 0
      System.out.println((a < 1 && ++b != 0) + ", " + b);    // false, 0 

      비트 연산자

      피연산자를 비트단위로 논리 연산한다.

      값을 2진수로 표현했을 때 각 자리를 규칙에 따라 연산을 수행한다.

      정수형과 문자형에서만 사용할 수 있다.

      기본적으로 int 타입간의 연산이다.

      • &  그리고

           피연산자 모두 1이어야만 1. 그 외는 0을 반환

      • |  또는

           피연산자 중 하나만 1이어도 1. 그 외는 0을 반환

      • ^  배타적

           피연산자의 값이 서로 다를 때만 1. 그 외는 0을 반환

      • 비트 전환 연산자 ~

           2진수에서 0은 1로, 1은 0으로 변경한다.

           1의 보수 연산자 :  부호 있는 피연산자는 전환 된 값(1의 보수)에 1을 더하면 부호가 반대인 값으로 바뀐다.

      10진수2진수의미
      1000001010
      -111111010110의 1의 보수
      • 쉬프트 연산자 << >>

           피연산자를 2진수로 표현했을 때 오른쪽 또는 왼쪽으로 이동한다.

           왼쪽으로 이동시키는 경우, 빈 자리를 0으로 채운다.

           오른쪽으로 이동시키는 경우, 부호에 따라 양수는 0, 음수는 1로 채워진다.

      10 « 2-10 « 210 » 2-10 » 2
      이동 전00001010111110100000101011111010
      001010<< 111010<<>>000010>>111110
      이동 후00101000111010000000001011111110
      • 예시)  x = 10101010, y = 00001111일 때
      x & yx | yx ^ y~xx « 1
      0000101010101111101001010101010101010100

      삼항 연산자 (조건 연산자) ?:

      조건식 ? 식1 : 식2

      피연산자인 조건식이 true면 식1을 수행하고, false면 식2를 수행한다.

      가독성을 위해 조건식을 괄호로 감쌀 수 있다.

      여러 번 중첩하면 가독성이 떨어지므로 한 번 정도만 중첩한다.

      int x = 2;
      result = (x = 2) ?  1 : (x < 2 ? 0 : -1);
            // (x = 2) ?  1 : (2 < 2 ? 0 : -1);
            // (x = 2) ?  1 : (false ? 0 : -1);
            // (2 = 2) ?  1 : -1;
            // (true) ?  1 : -1;
            // result = 1;

      대입 연산자   =  op=

      lvalue = rvalue

      변수와 같은 저장 공간에 값 또는 수식의 연산 결과를 저장한다.

      • lvalue(left value)

           변수, 식, 상수 등 모두 사용 가능하다.

      • rvalue(right value)

           변수처럼 값을 변경할 수 있는 것이어야 한다.

      • 복합 대입 연산자

           다른 연산자(op)와 결합하여 'op='와 같은 방식으로 사용될 수 있다.

           결합된 두 연산자는 공백없이 붙여 써야 한다.

      op==op==
      i += 2;i = i + 2i &= 2;i = i &+ 2
      i -= 2;i = i - 2i |= 2;i = i | 2
      i *= 2;i = i * 2i ^= 2;i = i ^ 2
      i /= 2;i = i / 2i «= 2;i = i « 2
      i %= 2;i = i % 2i *= 2 + J;
      i = i * (2 + J)

      참고 서적: 자바의 정석 3판 - 남궁 성 지음