ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JAVA 연산자
    JAVA/Java 2020. 11. 29. 00:18

    산술 연산자


     

    • 수학에서의 산술 연산자에는 사칙연산이 있다.
    • 더하기, 빼기, 곱하기, 나누기를 의미한다. 그렇다면 컴퓨터는 어떨까?

     

    • Java는 다섯 가지 연산이 있다. 
    • 더하기, 빼기, 곱하기, 몫, 나머지이다. 이때 곱하기, 나누기 부분에 차이가 있고 이에 대해 알아보자.

     

    핵심은 곱하기와 나누기의 연산 방식이 비트를 Shift하며 계산을 한다는 특징이 있다.

    몫과 나머지를 구하는데 최적화되어있기 때문이다.

    물론 소수 출력의 경우는 변수의 Data Type을 실수형으로 사용하면 부동소수점의 활용으로 가능하다.

     


     

     

     

    • 더하기는 "+", 빼기는 "-", 곱하기는 "*"로 사용 가능하다.
    • 앞서 말해 나누기가 수학에서의 사칙 연산과는 다른데 나누기에는 두 가지 연산 몫과 나머지 연산이 있고
    • "/"와 "%"로 보기와 같은 사용이 가능하다.

     

    • 다음의 예는 정수형 타입의 결과이고 변수의 Data Type을 실수형으로 바꾼다면 다음의 결과가 나온다.

     

    • 몫 연산의 부분이 정수일 때와 다르다. 소수점 자리가 16자리까지 나오며
    • 이는 double의 가수부 정밀도가 15~16자리이기 때문이다. 
    • format을 사용하면 원하는 소수점까지 잘라서 출력이 가능하다.

     

     

    주의할 점

     

    • 피연산자가 정수형인 경우, 나누는 수로 0을 사용하게 될 시 해당 Exception이 발생한다. 
    • 0이 아닌 부동 소수점 값을 사용하는 것은 가능하지만 이 경우 무한대가 반환된다.
    • ArithmeticException 발생할 수 있으니 조심하자.

     

     

    단항 연산자


     

     

     

     

    • 처음 n1과 n2이 6과 2로 찍힌 것을 볼 수 있다.
    • 그다음 n1과 n2는 뭐가 뜰까? 답은 7과 2다. 곧 배울 논리 연산자에서 ||는 첫 조건이 틀릴 시 나머지 조건을
    • 검사하지 않기 때문이다.

     

    비트 연산자


    • 비트 연산자를 살펴보기 전에  값이 컴퓨터에 어떻게 저장이 되는지 살펴보자.
    • 만약 176이라는 숫자가 컴퓨터에 저장된다면 이 수는 2진법으로 변환되어 10110000으로 저장된다.
    • 여기서 0과 1로 이루어진 한 자리, 한 단위를 "비트(bit)"라고 하고 이 비트가 8개 모인 것을 "바이트(Byte)"라고 한다.

     

    • 각 비트에 대해서 연산을 하여 비트 연산자라고 한다. 비트 연산자는 데이터를 비트 단위로 연산하기 때문에 
    • 0과 1로 표현 가능한 정수 타입만 비트 연산이 가능하다.

     

     

    • 먼저 Shift 연산은 비트 이동 연산자라고 하며 다음과 같이 세 가지 연산자가 있다.

     

    • 좀 더 자세히 -176이라는 숫자와 3이라는 숫자를 갖고 각 연산을 살펴보자. 각 숫자를 비트로 표현 시 다음과 같다.

     

    • -176 << 3을 하게 되면 왼쪽으로 3비트를 이동시킨다. 이를 표로 보면 다음과 같다.

     

    • 주의할 점은 컴퓨터에서 음수는 최상단 비트, MSB를 1로 두는데 이는 2의 보수로 음수를 구하기 때문이다.
    • 그래서 << 연산으로 왼쪽으로 3 만큼 이동하면 왼쪽으로 밀린 빨간색 111은 버려지고 파란색 000 이 채워진다.
      연산의 결과는 -1408이 된다. 실제로 코드로 결과를 살펴보면 다음과 같이 나온다.

     

     

    비트 보수 

    • ~ 연산자는 비트 반전 또는 비트 NOT 연산자라고 한다.
    • 각 비트를 반전시켜 1을 0으로, 0을 1로 변환한다.

     

    int i = ~1;
    byte b = ~1;

     

     

    • 위 예제에서 i와 b의 값은 무엇이 들어가 있을까? 출력을 해보면 둘 다 -2가 나온다.
    • 다만 디버거를 사용하여 바이너리 값으로 보면 아래와 같이 조금 다르게 나오는 것을 볼 수 있다.
    • 이유는 int는 32bit이고 byte는 8bit이기 때문이다.

     

    AND (&)

    • & 연산자는 두 정수 피연산자를 AND 연산한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    int num1 = 10;
    int num2 = 20;
     
    int result1 = num1 & num2; // 0
     
    int num3 = 11;
    int num4 = 15;
     
    int result2 = num3 & num4; // 11
    cs
    • rresult1과 result2의 결과가 왜 0과 11일까?
    • 비트곱은 두 피연산자의 해당 비트가 모두 1일 때만 1, 아니면 0을 리턴하기 때문이다.

     

     

    OR (|)

    • | 연산자는 두 정수 피연산자를 OR 연산합니다. (비트합)

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    int num1 = 10;
    int num2 = 20;
     
    int result1 = num1 | num2; // 30 (0b00011110)
     
    int num3 = 11;
    int num4 = 15;
     
    int result2 = num3 | num4; // 15 (0b00001111)
    cs

     

    • AND 연산 예제와 다르게 비트를 합한 결과가 나오게 된다.

     

    XOR (^)

    • ^ 연산자는 두 정수 피연산자를 XOR (exclusive OR) 연산을 한다
    • 두 피연산자의 해당 비트가 같으면 0, 다르면 1을 리턴한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int num1 = 10;
    int num2 = 20;
     
    int result1 = num1 ^ num2; // 30 (0b00011110)
     
    int num3 = 11;
    int num4 = 15;
     
    int result2 = num3 ^ num4; // 4 (0b00000100)
     
    cs

     

    관계 연산자


    • 같거나 같지 않음을 평가하는 비교 연산자(Comparison Operators)
    • 크고 작은 관계를 평가하는 관계 연산자(Relational Operators)
    • boolean 결과를 도출하므로 조건문(if)이나 반복문 (for, while) 등에서 결정을 위해 사용

     

    Equals (==)

    • == 연산자는 Primitive Type를 비교할 때 두 피연산자의 값이 같다면 true를 그렇지 않다면 false를 리턴한다.
    • 그러나 참조 타입의 피연산자를 비교하면 주소 값을 보고 동일한 객체 인지 여부를 체크한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int num1 = 10;
    int num2 = 10;
     
    num1 == num2 // true
     
    int num3 = 12;
    int num4 = 13;
     
    num3 == num4 // false
     
    cs

     

    • 두 피연산자의 타입이 다를 때는 크기가 작은 피연산자 타입이 큰 피연산자의 타입으로 변환되어 비교된다.
    1
    2
    3
    4
    int i = 10;
    float f = 10.0f;
     
    == f // true
    cs

     

    • 위 예제에서 i는 float 타입으로 변환된 후 비교된다.
    • 부동소수점의 NaN의 경우엔 모든 숫자와 같지 않으며
    • NaN 여부를 체크하려면 Float.isNan()이나 Double.isNan()을 사용해야 한다.

     

    Not Equals (!=)

    • != 연산자는 == 연산자와 정반대로 두 피연산자의 값이 다른지 여부를 체크하여 true/false를 리턴한다.
    •  참조 타입일 경우엔 동일한 객체 인지 여부를 체크한다.

     

    작음 (<), 작거나 같음 (<=)

    • 첫 번째 피연산자가 두 번째 피연산자보다 작은지 여부를 평가(Evaluate)하려면 < 연산자를 사용하고
    • 같은지 여부까지 평가하려면 <= 연산자를 사용한다.

     

    큼 (>), 크거나 같음 (>=)

    • 위 연산자와 정반대로 첫번째 피연산자가 두번째 피연산자보다 큰지 여부를 평가하기 위해 > 연산자를 사용하고
    • 같음 여부도 평가하려면 >= 연산자를 사용한다.

     

    논리 연산자

    • Boolean Operators라고도 하며 관계 연산자와 동일하게 true/false 결과를 리턴한다.
    • 여러 비교 연산을 사용하여 복잡도를 높인 조건식을 만들 때 주로 사용된다.

     

    조건부 AND (&&)

    두 피연산자가 모두 true인지 여부를 평가하며 두 피연산자 중 하나라도 false라면 false를 리턴한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int num1 = 10;
    int num2 = 10;
     
    boolean c1 = num1 >= num2; // true
     
    int num3 = 12;
    int num4 = 13;
     
    boolean c2 = num3 > num4; // false
     
    System.out.println(c1 && c2); // false
     
    cs

     

    조건부 OR (||)

    두 피연산자 중 하나라도 true 라면 true를 리턴한다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int num1 = 10;
    int num2 = 10;
     
    boolean c1 = num1 >= num2; // true
     
    int num3 = 12;
    int num4 = 13;
     
    boolean c2 = num3 > num4; // false
     
    System.out.println(c1 || c2); // true
     
    cs

     

    단락 회로 평가 (Short Circuit Evaluation)

    &&와 || 연산을 사용할 때 첫 번째 피연산자의 결과에 따라 결과 값이 정해졌을 때 두 번째 피연산자의 평가를 하지 않는 것을 말한다.

    • && : 첫 번째 피연산자의 결과가 false 라면 두 번째 피연산자를 평가하지 않고 false 리턴
    • || : 첫 번째 피연산자의 결과가 true 라면 두 번째 피연산자를 평가하지 않고 true 리턴

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public boolean isTrue() {
        System.out.println("isTrue");
        return 10 >= 10;
    }
     
    public boolean isFalse() {
        System.out.println("isFalse");
        return 12 > 13;
    }
    cs

     

    • 위와 같은 메소드가 있고 &&, || 를 사용하여 비교한다면 피연산자 순서에 따라 출력이 다르다.
    • 출력 결과는 아래와 같다.
    1
    2
    3
    4
    5
    6
    isTrue() && isFalse(); // isTrue, isFalse
    isFalse() && isTrue(); // isFalse
     
    isTrue() || isFalse(); // isTrue
    isFalse() || isTrue(); // isFalse, isTrue
     
    cs

     

    부정 연산자 (!)

    단항 연산자로써 해당 값의 결과의 반대로 평가한다.

    위 isTrue와 isFalse 메서드를 대상으로 사용해보면 아래와 같다.

     

    1
    2
    3
    !isTrue() // false
    !isFalse() // true
     
    cs

     

    AND (&), OR (|), XOR (^)

    • 비트 연산에서 사용되었던 연산자들과 동일하지만 boolean 연산을 사용할 때도 이 연산자들을 사용할 수 있다.
    • &와 |의 경우 &&와 ||의 결과와 동일하지만 단락 회로 평가가 되지 않는다.
    • ^ 연산자는 두 피연산자 중 하나만 true라면 true를 리턴한다. 이 연산자도 위 두 연산자와 동일하게 단락 회로 평가가 되지 않는다.

     

    instanceof

      • 객체(Object) 또는 배열(Array) 값을 어떠한 참조 유형에 맞는 값인지를 평가하는 연산자이다.
      • 만약 null을 평가한다면 항상 false가 리턴된다.
      • 만약 평가 결과가 true라면 비교된 참조 유형으로 안전하게 캐스팅하고 할당할 수 있다는 것을 의미한다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    "sangwoo" instanceof String // true
    null instanceof String // false
     
    Object o = new int[]{123};
    instanceof int[] // true
     
    // safety casting
    if (obj instanceof MyClass) {
        MyClass c = (MyClass) obj;
    }
     
    instanceof int // compile error : Primitive Type은 사용할 수 없습니다.
    cs

     

     

    'JAVA > Java' 카테고리의 다른 글

    자바 데이터 타입, 변수, 배열  (0) 2020.12.26
    Maven에 대해서 알아보자  (0) 2020.08.30
    서블릿 Life Cycle 알아보기  (0) 2020.06.02
    왜 Wrapper 클래스는 쓰이는 걸까?  (1) 2020.05.21
    객체의 해시코드(hashCode())란  (0) 2020.05.19
Designed by Tistory.