연산자

박영준·2022년 11월 8일
0

Java

목록 보기
63/112

1. 정의

  • 연산자 : 연산에 사용되는 표시나 기호

    피연산자 : 연산되는 데이터

  • 단, 연산결과를 반환하지 않으면 연산자가 아니다.

    • () -> 괄호는 연산자가 아니다.

2. 처리 순서

1) 기본 처리

2) 괄호 ( )

괄호 ( )를 사용해서 우선 연산 가능

3) 왼쪽 ↔ 오른쪽

일반적인 연산자 : 왼쪽 → 오른쪽 방향으로 연산
단항 연산자, 대입 연산자 : 왼쪽 ← 오른쪽 방향으로 연산

// 예시
class Main {
	public static void main(String[] args) {
    	int x, y;
        
        x = y = 3;			// y 에 3 저장된 후, x에 3 저장됨
        
        System.out.println(...);
    }
}

3. 종류

1) 단항 연산자

(1) 부호 연산자 +, -

2 순위

byte b = 100;
byte result = -b		// 컴파일 에러
int result = -b
  • char타입(정수), boolean타입(논리)을 제외하고 모두 사용 가능

  • 연산 결과는 int 타입(정수)

(2) 증감 연산자 ++, --

1순위

int x = 1;
int y = 1;
int result1 = ++x + 10;		// x + 1 = 2 + 10 = 12
int result2 = y++ + 10;     // y + 10 = 11, y = 2 
  • boolean타입(논리)을 제외하고 모두 사용 가능

  • ++i 와 i++ 은 연산 속도 차이 X

  • x++, ++x 구분 필요!

    • x++, x-- : 값이 참조된 후에 증가/감소
    • ++x, --x : 값이 참조되기 전에 증가/감소
    • 단, 증감 연산자가 독립적으로 사용된 경우 전위형과 후위형의 차이 X
      (++k; 과 k++ 는 값이 동일함)

    Q. 다음 코드를 실행했을 때 출력 결과는 무엇입니까?

    int x = 10;
    int y = 20;
    int z = (++x) + (y--);
    System.out.println(z);

    A. 출력 결과 : 31
    ++X 에서 증가 연산자 ++은 다른 연산을 수행하기 전에, 피연산자 x의 값을 1 증가시킨다.
    y--에서 감소 연산자 --는 다른 연산을 수행한 후에, 피연산자 y의 값을 1 감소시킨다.

    따라서, int z = (1+10) + (20) = 31이 저장된다.
    그 이후에, y는 감소 연산을 수행하여 19가 된다.

(3) 논리 부정 연산자 !

1 순위

boolean play = true;
System.out.println(play);
        
play = !play;
System.out.println(play);
        
play = !play;
System.out.println(play);		// false를 부정

/* 실행결과
true
false
true */
  • boolean타입(논리)만 사용 가능
    → true/false 가 서로 변경됨

  • 조건문, 제어문에서 사용 : 조건식의 값 부정하도록 해서

  • 토글 기능 구현에 사용 : 두 가지 상태(true/false) 번갈아 번경해서

2) 이항 연산자

(1) 산술 연산자 +, -, *, /, %

2 순위

double result3 = (int1 * 1.0) / int2;
double result3 = (double) int1 / int2;
double result3 = int1 / (dobule) int2;
  • 피연산자 타입을 동일하게 만든다

    • byte, short, char → 모두 int 타입 으로 변환 후, 연산 (연산 결과를 char 타입에 저장하면, 컴파일 에러 발생)
    • 모두 정수 타입(byte, short, char, int, long) + long 타입 포함 → 모두 long 타입으로 변환 후, 연산
    • 실수 타입(float, double) 포함 → 모두 double 타입으로 변환 후, 연산
  • 2.5 산출하는 법
    Q. 다음 코드를 실행하면 출력 결과로 5를 기대했는데 4가 출력되었습니다. 어디에서 잘못 작성된 것일까요?

    int var1 = 5;
    int var2 = 2;
    
    double var3 = var1 / var2;
    
    int var4 = (int)(var3 * var2);
    
    System.out.println(var4);

    A.
    int형 데이터끼리의 연산은 항상 int형 데이터(정수 타입)로 나온다.

    따라서, double var3 은 2.5가 아닌 2가 되고
    int var4 는 4 가 된다.

    만약, va1 과 var2 中 최소 1 개라도 double/float(실수 타입)로 강제 변환 했다면,
    모두 double 타입으로 변환되어 연산 결과는 2.5가 나왔을 것이다.
    이때 최종 출력 결과는 5가 될 수 있다.

    참고: 타입

  • 음수와 나누기(%)

    • 일단 피연산자의 부호(-)를 무시하고 % 연산을 한 후, 나온 값에 왼쪽 피연산자의 부호를 붙인다.
      class Main {
          public static void main(String[] args) {
              System.out.println(-10 % 8);		// -2
              System.out.println(10 % 8);			// 2
              System.out.println(-10 % -8);		// -2
          }
      }

(2) 문자열 결합 연산자

(* 타입 변환 中 자동 타입 변환 中 연산에서 문자열 자동 타입 변환 참고)

“JDK” + 3 + 3.0;>     “JDK3” + 3.0;>     “JDK33.03 + 3.0 + “JDK”      —>     6.0 + “JDK”       —>6.0JDK”

참고: 타입 - 자동 타입 변환 - 5. 연산에서 문자열 자동 타입 변환

(3) 시프트 연산자 >>, <<, >>>

3 순위

int x = 64;   // -64;
int n = 2;        
System.out.println("x >> n = " + (x >> n)); 	// 나눗셈, (x / 2^n)
System.out.println("x << n = " + (x << n)); 	// 곱셈,  (x * 2^n)
System.out.println("x >>> n = " + (x >>> n));

System.out.println("x >> 34 = " + (x >> 34));    // x / 2^(n % 32)
System.out.println("x << 34 = " + (x << 34));
System.out.println("x >>> 34 = " + (x >>> 34));
  • >> : bit값을 오른쪽으로 이동 (빈 자리는 부호값으로 대입) 한다.
    << : bit값을 왼쪽으로 이동 (빈 자리는 0으로 대입) 한다.
    >>> : bit값을 오른쪽으로 이동 (빈 자리는 0으로 대입) 한다.

(4) 비교 연산자 <, <=, >, >=, ==, !=

4 순위

// 0.1f의 근사값은 0.1보다 큰 값이 나오기 때문
0.1 == 0.1f   // false
            
/* 해결법
 1. 모두 float 타입으로 변환
 2. 정수 타입으로 변환        */
  • 대소 연산자(<, <=, >, >=) : boolean타입(논리)을 제외하고 모두 사용 가능

    동등 연산자(==, !=) : 모두 사용 가능 (!= 는 두 피연사자의 값이 다른지 검사)

  • 조건문(if), 반복문(for, while)에 주로 사용

  • char 타입 : 유니코드 값으로 비교 연산

  • 피연산자 타입을 동일하게 만든다

  • ~이상 ~이하에서 조건식을 작성할 경우
    -100 <= num <= 100 (X)
    -100 <= num && num <= 100 (O) 처럼 따로 작성해줘야한다.

  • String 변수 비교에는 equals() 메소드를 사용
class Operator6_1 {
    public static void main(String[] args) {
        int n1 = 10, n2 = 6;
        char c1 = 'A', c2 = 'B';

        System.out.print("n1 >= n2 = " ); // true
        System.out.println(n1 >= n2);
        System.out.print("n1 <= n2 = " ); // false
        System.out.println(n1 <= n2);

        System.out.print("n1 == n2 = " ); // false
        System.out.println(n1 == n2);
        System.out.print("n1 != n2 = " ); // true
        System.out.println(n1 != n2);

        // 산술변환 규칙에 의해서 char 타입이 int 타입으로 변환되어 연산됨
        System.out.print("c1 < c2 = "); // true
        System.out.println(c1 < c2); // 65 < 66
        System.out.print("c1 > c2 = "); // false
        System.out.println(c1 > c2); // 65 > 66
    }
}
  • 두 피연산자를 비교해서 true(참) 또는 false(거짓)를 반환

(5) 논리 연산자 &&, ||, &, |, ^, !

! 는 1 순위
&, |, ^ 는 5 순위
&&, || 는 6 순위

  • boolean타입(논리)만 사용 가능

  • &&, || 는 &, | 보다 효율적으로 동작함
    → 앞의 연사자가 false 라면, 뒤의 연산자를 평가하지 않고 바로 false라는 산출 결과를 내기 때문

  • 예시

    System.out.println(true || true)			// true
    System.out.println(true || true || false)	// true
    System.out.println(true && false	)		// false
    System.out.println(true && true)			// true
    
    System.out.println(true)			// false
    • || (or) : 하나라도 true 이면 true
    • && (and) : 모두 true 이면 true
    • !를 붙으면 반대가 나옴

(6) 대입 연산자 =, +=, -=, /=, %=, *=

8 순위

① 정의

  • 단순 대입 연산 : 오른 쪽 피연산자의 값을 변수에 저장

  • 복합 대입 연산 : 정해진 연산 수행 후, 결과를 변수에 저장

② 종류

  • = : 왼쪽의 피연산자에 오른쪽의 피연산자를 대입

  • += : 왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • -= : 왼쪽의 피연산자에서 오른쪽의 피연산자를 뺀 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • *= : 왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • /= : 왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • %= : 왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 왼쪽의 피연산자에 대입

  • &= : 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • != : 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • ^= : 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • <<= : 왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • >>= : 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입

  • >>>= : 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입

③ 주의점

  1. class Operator8_2 {
        public static void main(String[] args) {
            int num1 = 7, num2 = 7, num3 = 7;
    
            num1 = num1 - 3;
            num2 -= 3;
            num3 =- 3;
    
            // = 위치를 주의
            System.out.println("=- 연산자에 의한 결과 : "+ num3);		// -3
        }
    }
    • num3 =- 3; 는 num3 = -3
  2. i *= 10 + j
    
    // 올바른 풀이
    i = i * (10 + j)
    
    // 잘못된 풀이 : i * 10이 먼저 연산이 돼버린다.
    i = i * 10 + j

(7) 비트 연산자 &, |, ^, ~, <<, >>, >>>

① 정의

  • 값을 비트 단위로 연산
  • 0과 1로 표현이 가능한 정수형이나 형변환이 가능한 자료형만 연산이 가능

② 종류

  • & : 대응되는 비트가 모두 1이면 1을 반환함. (비트 AND 연산)

  • | : 대응되는 비트 중에서 하나라도 1이면 1을 반환함. (비트 OR 연산)

  • ^ : 대응되는 비트가 서로 다르면 1을 반환함. (비트 XOR 연산)

  • ~ : 비트를 1이면 0으로, 0이면 1로 반전 시킴. (비트 NOT 연산, 1의 보수)

  • << : 명시된 수만큼 비트들을 전부 왼쪽으로 이동시킴. (left shift 연산)

    • 자리수를 왼쪽으로 옮기는 횟수만큼 2의 배수로 곱셈 연산되는 것과 동일
  • >> : 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴. (right shift 연산)

    • 자리수를 오른쪽으로 옮기는 횟수만큼 2의 배수로 곱셈 연산되는 것과 동일
    • 0101(= 숫자 5) -> 1010(= 숫자 10)
  • >>> : 지정한 수만큼 비트를 전부 오른쪽으로 이동 시키며, 새로운 비트는 전부 0이 됨

③ 예시

class Operator7_2 {
    public static void main(String[] args) {
        int num1 = 8, num2 = -8;
        System.out.println("8의 2진수 = " + Integer.toBinaryString(num1)); // 0 생략 가능!
        System.out.println("-8의 2진수 = " + Integer.toBinaryString(num2));
        System.out.println("-9의 2진수 = " + Integer.toBinaryString(-9)); // 32bit, int = 4byte

        // 00000000000000000000000000001000 ,  8
        // 11111111111111111111111111111000 , -8
        System.out.println("& 연산자에 의한 결과 = " + (num1 & num2)); // 00000000000000000000000000001000, 8
        System.out.println("| 연산자에 의한 결과 = " + (num1 | num2)); // 11111111111111111111111111111000, -8
        System.out.println("^ 연산자에 의한 결과 = " + (num1 ^ num2)); // 11111111111111111111111111110000, -16

        System.out.println("~ 연산자에 의한 결과 = " + ~num1); // 11111111111111111111111111110111, -9

        System.out.println("<< 연산자에 의한 결과 = " + (num1 << 2)); // 32
        System.out.println(">> 연산자에 의한 결과 = " + (num2 >> 2)); // -2

        System.out.println(">>> 연산자에 의한 결과 = " + (num2 >>> 2)); // 1073741822
    }
}

참고: 2진수의 음수표현

3) 삼항 연산자 (= 조건 연산식)

?, : 는 7 순위

  조건식   ?   값 또는 연산식   :   값 또는 연산식
(피연산자1)     (피연산자2)          (피연산자3)
    
// 예시
// score는 85점 이므로, false -> ((score > 80) ? 'B' : 'C')  -> score는 85점 이므로, true -> B
int score = 85;
char grade = (score > 90) ? 'A' : ((score > 80) ? 'B' : 'C');
System.out.println(score + "점은" + grade + "등급입니다.");

/* 실행결과
85점은 B등급입니다.
*/
  • 조건식 연산 → true가 나오면 결과는 피연산자2, false가 나오면 결과는 피연산자3
  • if 문 보다 삼항 연산자가 효율적이다. (한 줄에 간단하게 작성 가능하기 때문)

우선순위 연습하기

class Operator1_1 {
    public static void main(String[] args) {
        int x = 10;
        int y = 20;

        // + 연산자는 피연산자가 2개인 이항 연산자 임으로 단항 연산자인 -x 의 -가 먼저 실행된다.
        System.out.print("-x + 3 = ");
        System.out.println(-x + 3); // -10 + 3 = -7

        System.out.print("x + 3 * y = ");
        System.out.println(x + 3 * y); // 10 + (3 * 20) = 70

        System.out.print("x + 3 > y - 2 = ");
        System.out.println(x + 3 > y - 2); // false
        System.out.print("x + 3 < y - 2 = ");
        System.out.println(x + 3 < y - 2); // true

        System.out.print("x > 3 && y < 2 = ");
        System.out.println(x > 3 && y < 2); // false

        int result = x + y * 3;
        System.out.println("result = " + result); // 10 + (20 * 3), result = 70
    }
}


참고: [Java] 자바 연산자 (Java Operator)
참고: 산술 연산자

profile
개발자로 거듭나기!

0개의 댓글