PART 02 연산자

조재형·2023년 5월 3일
0

스터디

목록 보기
2/19
post-thumbnail

연산자

연산자와 피연산자 구별하기

9 * x + 3

  • 연산자 : 연산을 수행하는 기호 -> * , +
  • 피연산자 : 연산자의 연산 수행 대상 -> 9, x, 3

"모든 연산자는 연산결과를 반환한다."
즉, 연산결과를 반환하지 않으면 연산자가 아니다.
ex) ()괄호는 연산자가 아님.

연산자의 종류

  • 산술 연산자
    산술 연산자의 종류에는 +, -, *, /, %, <<, >> 가 있다.
    사칙 연산과 나머지 연산(%) 기호들이다.

  • 비교 연산자
    비교 연산자의 종류에는 <, >, >=, <=, ==, !=가 있다.
    크고 작음과 같고 다름을 비교한다.

  • 논리 연산자
    논리 연산자의 종류에는 &&, ||, !, &, |, ^, ~가 있다.
    '그리고(AND)'와 '또는(OR)'으로 조건을 연결한다.

  • 대입 연산자
    대입 연산자 기호는 = 이다.
    우변의 값을 좌변에 저장한다.

  • 기타 연산자
    기타 연산자에는 (type) ?:instanceof 가 있다.
    형변환 연산자, 삼향 연산자, instanceof 연산자 이다.

연산자의 우선순위는

  1. 산술 > 비교 > 논리 > 대입 : 대입은 제일 마지막에 수행된다.
  2. 단항(1) > 이항(2) > 삼항(3) : 단항 연산자의 우선순위가 제일 높다.
  3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행 방향은 왼쪽에서 오른쪽이다.

증감 연산자와 부호 연산자

  • 증감 연산자

    증가 연산자(++) : 피연산자의 값을 1 증가시킨다.
    감소 연산자(--) : 피연산자의 값을 1 감소시킨다.

타입설명사용예
전위형값이 참조되기 전에 증가/감소 시킨다.k == +j;
k = --j;
후위형값이 참조된 후에 증가/감소 시킨다.k == j++;
k == j--;
  • 부호 연산자

    ' - ' 는 피연산자의 부호를 바대로 변경한다.
    ' + ' 는 아무런 일도 하지 않는다. (실제로 사용하지 않음)

형변환 연산자와 자동 형변환

  • 형변환 연산자

    형변환이란?
    : 변수 또는 상수의 타입을 다른 타빙으로 변환 하는 것을 의미한다.
    (type)피연산자

    변환수식
    int -> char(char)65
    char -> int(int)'A'
    float -> int(int)1.6f
    int -> float(float)10


  • 예제코드

    class Operator3_1 {
    public static void main(String[] args) {
    int i = 65, num = 10;
    char ch = 'A';
    float f = 1.6f;

    System.out.println("(char)i = " + (char)i);
    System.out.println("(int)ch = " + (int)ch);
    System.out.println("(int)f = " + (int)f);
    System.out.println("(float)num = " + (float)num);
    }
    }

자동 형변환

float f = 1234; => int 타입의 값을 float 타입의 변수에 저장한다.

  • 상대적으로 int 타입이 float 타입 보다 크기가 작기 때문에 가능합니다.
    float f = (float)1234; => 사실 변수와 리터럴의 타입을 일치 시켜줘야 합니다.
  • 우리가 보는 코드에는 형변환이 생략되어 있었습니다.
    즉, 컴파일러에 의해 자동으로 형변환된 것입니다.

int i = 3.14f;

  • 이렇게 큰 타입을 작은 타입에 저장할 때 Error가 발생합니다.
  • 3.14f 가 int 타입으로 변환될 때 소수점이 사라지면서 원래 값이 달라집니다.
  • 즉, 값 손실이 발생하는데 이런 경우, 컴파일러가 자동으로 형변환을 안 해줍니다.

int i =(int)3.14f; =>이렇게 직접 수동으로 형 변환을 시켜주어야 합니다.

"기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환된다."

  • 형변환을 하는 이유는 주로 서로 다른 두 타입을 일치시키기 위해서인데, 형변환을 생략하려면 컴파일러가 알아서 자동으로 형변환을 해야합니다.
  • 따라서 표현범위가 좁은 타입에서 넓은 타입으로 형변환하는 경우에는 값 손실이 없음으로 두 타입 중에서 표현 범위가 더 넓은 쪽으로 형변환됩니다.
  • 예제코드
    class Operator3_2 {
    public static void main(String[] args) {
    // 큰 타입을 작은 타입에 저장!
    // int i = 3.14f; // Error 발생
    int i = (int)3.14f; // 형변환 필요!
    System.out.println("i = " + i);

    // 예외 경우 확인


    // 100 은 int 타입 따라서 아래 코드는 현재 큰 타입(int)을 작은 타입(byte)에 넣고 있음!
    // 컴퓨터는 byte의 범위가 -128 ~ 127 인 것을 알고 있다.
    // 따라서 100을 byte b 에 집어 넣어도 값 손실이 발생하지 않는 다는 것을 알기 때문에
    // 자동으로 형변환을 해준다.
    // byte b = (byte)100; -> 컴파일러가 자동 형변환
    byte b = 100; // OK
    System.out.println("b = " + b);


    // 위의 경우는 100 은 리터럴 즉, 상수이기 때문에 컴파일러가 값을 명확하게 알지만
    // 아래 num 은 변수, 따라서 확신할 수 없기 때문에 Error 발생
    int num = 100;
    // byte b2 = num; // Error 발생
    byte b2 = (byte) num; // byte 타입으로 형변환
    System.out.println("b2 = " + b2);


    // byte b3 = 1000; // Error 발생, 범위를 넘어감
    byte b3 = (byte) 1000;
    // OK, 그러나 값 손실 발생, b3 에는 -24 가 저장됨
    // 즉, 상수여도 값 손실이 일어나면 자동 형변환 불가능!
    System.out.println("b3 = " + b3);
    }
    }

사칙 연산자와 산술변환

사칙 연산자

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

  • 예제코드
    class Operator4_1 {
    public static void main(String[] args) {
    int a = 10, b = 4;


    // 덧셈
    System.out.print("a + b = ");
    System.out.println(a + b);


    // 뺄셈
    System.out.print("a - b = ");
    System.out.println(a - b);


    // 곱셈
    System.out.print("a b = ");
    System.out.println(a
    b);


    // 나눗셈
    // 소수점 이하는 버려진다.
    System.out.print("a / b = ");
    System.out.println(a / b);


    // 10 / 4.0f -> 10.0f / 4.0f -> 2.5
    System.out.print("a / (float)b = ");
    System.out.println(a / (float)b);
    }
    }

산술변환

연산 전에 피연산자의 타입을 일치시키는 것을 의미한다.

1. 두 피연산자의 타입을 같게 일치시킨다.
(보다 큰 타입으로 일치)

  • long + int -> long + long => long
  • float + int -> float + float => float
  • double + float -> double + double => double

  1. 피연산자의 타입이 int 보다 작은 타입이면 int로 변환된다.
  • byte + short -> int + int => int
  • char + short -> int + int => int
  • 이는 int 보다 작은 타입이 계산을 통해 쉽게 범위가 넘어갈 수 있기 때문에 오버플로우가 발생해,
    정확한 계산값을 가져오지 못할 수 있어서 미리 큰 범위인 int 타입으로 변환시킨 후 계산하는 것이다.
  • 예제코드

    class Operator4_2 {
    public static void main(String[] args) {
    char ch = '2';


    // 문자 '2' 는 숫자로 50, '0' 은 48
    // 따라서 int 타입으로 자동으로 변하기 때문에 50 - 48 = 2
    System.out.print("ch - '0' = ");
    System.out.println(ch - '0');


    int a = 1_000_000; // 1백만
    int b = 2_000_000; // 2백만


    // a b = 2_000_000_000_000 -> 10^12
    // long 에 저장하려는 것은 맞지만 a
    b 의 결과 타입이 int
    // 따라서 이미 계산을 할 때 오버플로우 발생! -> 따라서 계산을 할 때 형변환 필요!
    // long l = a b; // -1454759936


    long l = (long)a
    b;
    // long int -> long long => 1_000_000L 2_000_000 -> 1_000_000L 2_000_000L
    System.out.println("l = " + l);
    }
    }

Math 클래스와 나머지 연산자

  • Math

    • Math는 수학과 관련된 메서드를 가지고 있는 클래스이다.

    • 메서드는 '특정한 기능을 수행하기 위해 코드로 작성된 단위!' 라고 생각하면 된다.

      round() : 실수를 소수점 첫째자리 에서 반올림 한 정수를 반환
      cell() : 올림값을 double 형으로 반환
      floor() : 내림값을 double 형으로 변환
      abs() : int, double 기본형 모두 사용 가능하며 절대값을 얻는다.

    • 예제코드 1

      class Operator5_1 {
      public static void main(String[] args) {
      long result = Math.round(3.645678);
      System.out.println("result = " + result);


      // 소수점 4째 자리에서 반올림한 값을 구하라!
      double pi = 3.141592;
      // pi 1000 = 3141.592
      // Math.round(3141.592) = 3142
      // 3142 / 1000.0 = 3.142
      double shortPi = Math.round(pi
      1000) / 1000.0;
      System.out.println(shortPi); // 3.142


      // 3.141 구하기!
      double pi2 = 3.141592;
      // pi2 1000 = 3141.592
      // (int)3141.592
      System.out.println("(int)(pi2
      1000) = " + (int) (pi2 1000));
      System.out.println("(int)(pi2
      1000) / 1000.0 = " + (int) (pi2 * 1000) / 1000.0);
      }
      }

    • 예제코드 2

      class Operator5_2 {
      public static void main(String[] args) {
      double num = 3.14;


      System.out.println("반올림 : " + Math.round(num)); // 반올림 : 3
      System.out.println("올림 : " + Math.ceil(num)); // 올림 : 4.0
      System.out.println("내림 : " + Math.floor(num)); // 내림 : 3.0
      System.out.println("절대값 : " + Math.abs(num*-1)); // 절대값 : 3.14
      }
      }

나머지 연산자 %

  • 오른쪽 피연산자로 나누고 남은 나머지를 반환한다.
  • 나누는 피연산자는 0이 아닌 정수만 허용
  • 부호는 무시한다
  • 예제코드

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


    System.out.print("x를 y로 나눈 몫 = ");
    System.out.println(x / y);


    System.out.print("x를 y로 나눈 나머지 = ");
    System.out.println(x % y);


    // 부호 무시 확인
    int n = 3;
    int z = -3;
    System.out.println("x % n = " + x % n);
    System.out.println("x % z = " + x % z);
    }
    }

비교 연산자

비교 연산자설명
==왼쪽의 피연산자와 오른쪽의 피연산자가 같으면 참을 반환함
!=왼쪽의 피연산자와 오른쪽의 피연산자가 같지 않으면 참을 반환함
>왼쪽의 피연산자가 오른쪽의 피연산자보다 크면 참을 반환함
>=왼쪽의 피연산자가 오른쪽의 피연산자보다 크거나 같으면 참을 반환함.
<왼쪽의 피연산자가 오른쪽의 피연산자보다 작으면 참을 반환함.
<=왼쪽의 피연산자가 오른쪽의 피연산자보다 작거나 같으면 참을 반환함.
  • 두 피연산자를 비교해서 ture(참) 또는 false(거짓)를 반환한다.

  • 예제코드

    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
    }
    }

문자열의 비교

문자열 비교에는 == 대신 equals()를 사용해야 한다.

  • equals : 비교하고자 하는 두 피연산자의 값 자체를 비교한다
  • == : 비교하고자 하는 두 피연산자의 주소값을 비교한다
  • 지금은 '문자열 비교에는 == 대신 equals()를 사용해야 한다!'만 기억하면 된다.

  • 예제코드

    class Operator6_2 {
    public static void main(String[] args) {
    String s1 = "사랑";
    String s2 = "사랑";


    System.out.print("s1 == s2 = "); // true
    System.out.println(s1 == s2);
    System.out.println("s1.equals(s2) = " + s1.equals(s2)); // true


    // 하지만!
    String s3 = new String("사랑");
    System.out.print("s1 == s3 = "); // false
    System.out.println(s1 == s3);
    System.out.println("s1.equals(s3) = " + s1.equals(s3)); // true
    }
    }

논리 연산자

논리 연산자설명
&&논리식이 모두 참이면 참을 반환함.
(논리 AND 연산)
논리식 중에서 하나라도 참이면 참을 반환함.
(논리 OR 연산)
!논리식의 결과가 참이면 거짓을, 거짓이면 참을 반환함.
(논리 NOT 연산)


ABA&&BA∥B!A
truetruetruetruefalse
trueflasefalsetrueflase
flasetrueflasetreutrue
falsefalsefalsefalsetrue
  • 예제코드

    class Operator7_1 {
    public static void main(String[] args) {
    boolean result1, result2, result3, result4, reusult5, result6;


    char ch1 = 'a', ch2 = 'B'; // 'a' : 97 , 'A' : 65, 'B' : 66, 'C' : 67


    result1 = ch1 > 'A' && ch2 < 'C';
    result2 = ch1 == 'A' && ch2 < 'C';


    result3 = ch1 > 'A' || ch2 < 'C';
    result4 = ch1 < 'A' || ch2 > 'C';


    System.out.println("&& 연산자에 의한 결과 result1 = " + result1); // true
    System.out.println("&& 연산자에 의한 결과 result2 = " + result2); // false


    System.out.println("|| 연산자에 의한 결과 result3 = " + result3); // true
    System.out.println("|| 연산자에 의한 결과 result4 = " + result4); // false


    System.out.println("! 연산자에 의한 결과 result4 = " + !result4); // true


    System.out.println();


    int num = 10;
    // num 은 2의 배수 그리고 3의 배수이다.
    reusult5 = num % 2 == 0 && num % 3 == 0;
    System.out.println("num 은 2의 배수 그리고 3의 배수 = " + reusult5); // false


    // num 은 2의 배수 또는 3의 배수이다.
    result6 = num % 2 == 0 || num % 3 == 0;
    System.out.println("num 은 2의 배수 또는 3의 배수 = " + result6); // true
    }
    }

비트 연산자

비트연산자설명
&대응되는 비트가 모두 1이면 1을 반환함
(비트 AND 연산)
대응되는 비트 중에서 하나라도 1이면 1을 반환함
(비트 OR 연산)
^대응되는 비트가 서로 다르면 1을 반환함
(비트 XOR 연산)
~비트를 1이면 0으로, 0이면 1로 반전 시킴
(비트 NOT 연산, 1의 보수)
<<명시된 수 만큼 비트들을 전부 왼쪽으로 이동시킴
(left shift 연산)
>>부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴
(right shift 연산)
>>>지정한 수만큼 비트를 전부 오른쪽으로 이동시키며,
새로운 비트는 전부 0이 됨
  • 비트 연산자는 값을 비트 단위로 연산한다.

  • 따라서 0과 1로 표현이 가능한 정수형이나 형변환이 가능한 자료형만 연산이 가능함

  • 예제코드

    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진수의 음수 표현 방법은
    • 1.부호 절대값 (가장 왼쪽의 부호비트가 0일때 양수, 1이면 음수)
    • 1의 보수 ( 11111111 - x의 방식.x의 반전)
    • 2의 보수 ( 100000000 - x의 방식.
      ex) -13을 2의 보수로 표현한다면.
      13을 2진수로 표현 : 00001101
      100000000 - x 공식에 대입
      100000000
      -00001101
      =11110011
      결과 : 11110011
    • 쉽게 계산하는 방법은 1의 보수를 구한뒤, 나온 수에 +1을 하면 된다.
      => -9를 2의 보수 방식으로 표현
      1. -9를 1의 보수 방식으로 표현 :
        00001001(9)-> 11110110
      2. 11110110 + 1
      3. 결과 : 11110111

    조건 연산자와 대입 연산자

  • 조건 연산자

    삼항 연산자 : 조건식 ? 반환값 1 : 반환값2
    - 조건식의 결과에 따라 연산결과를 달리할 수 있다.

  • 예제코드

    class Operator8_1 {
    public static void main(String[] args) {
    int num1 = 5, num2 = 7;
    int result;


    result = num1 - num2 > 0 ? num1 : num2;


    System.out.println("두 정수 중 더 큰 수는 " + result + "입니다."); // 7
    }
    }

  • 대입 연산자

대입 연산자설명
=왼쪽의 피연산자에 오른쪽의 피연산자를 대입함
+=왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후,
그 결괏값을 왼쪽의 피연산자에 대입함
-=왼쪽의 피연산자에서 오른쪽의 피연산자를 뺀 후,
그 결과값을 왼쪽의 피연산자에 대입함
*=왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후,
그 결과값을 왼쪽의 피연산자에 대입함
/=왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후,
그 결과값을 왼쪽의 피연산자에 대입함
%=왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후,
그 결과값을 왼쪽의 피연산자에 대입함
&=왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후,
그 결과값을 왼쪽의 피연산자에 대입함
!=왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후,
그 결과값을 왼쪽의 피연산자에 대입함
^=왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후,
그 결과값을 왼쪽의 피연산자에 대입함
<<=왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 시프트한 후,
그 결과값을 왼쪽의 피연산자에 대입함
>>=왼쪽의 피연산자를 오른쪽의 피연산자만큼
부호를 유지하며 오른쪽 시프트한 후,
그 결과값을 왼쪽의 피연산자에 대입함
>>>=왼쪽의 피연산자를 오른쪽의 피연산자만큼
부호에 상관없이 오른쪽 시프트한 후,
그 결과값을 왼쪽의 피연산자에 대입함
  • 예제코드

    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("- 연산자에 의한 결과 : "+ num1); // 4
    System.out.println("-= 연산자에 의한 결과 : "+ num2); // 4


    // = 위치를 주의하셔야 합니다.
    // num3 =- 3; 는 num3 = -3 입니다.
    System.out.println("=- 연산자에 의한 결과 : "+ num3); // -3
    }
    }

profile
안녕하세요.

0개의 댓글