<Java> 연산자 2

비교 연산자

  • 지난 시간에 배웠던 산수 연산자에 이어서 비교 연산자부터 시작해보겠습니다.
  • 비교 연산자는 말 그대로 피연산자를 비교하는 데 사용되는 연산자입니다.주로 조건문과 반복문의 조건식에서 사용되며, 연산결과는 오직 true or false만을 반환합니다.
  • 비교 연산자는 이항 연산자이므로 산술 연산자와 마찬가지로 피연산자의 타입이 서로 다를 경우 자료형의 범위가 큰 쪽으로 자동 형변환하여 피연산자의 타입을 일치 시킨후 연산을 진행합니다.

대소비교 연산자

  • 저희가 너무나 익숙하게 사용하는 <,>,<=,>= 네가지 연산자입니다.
  • 각각 크다, 작다, 작거나 같다, 크거나 같다라는 비교를 진행해주며 조건이 만족되면 true, 그렇지 않을 시에는 false를 연산결과로 반환합니다.

등가비교 연산자

  • 용어 자체가 익숙하지 않을 뿐이지 마찬가지로 굉장히 직관적인 연산자입니다.
  • 두 피연산자들이 같은지 또는 다른지만을 비교하는 연산자입니다. == 과 =!으로 각각 같다, 다르다라는 비교 연산을 수행합니다.
  • 해당 연산자들은 Primitive Type은 물론 Reference Type까지 사용할 수 있습니다.기본형에 사용할 경우 변수에 저장되어있는 값이 같은지 알아볼 수 있으며, 참조형에 사용할 경우 객체의 주소값을 비교합니다.즉, 두개의 피연산자들이 동일한 객체를 가리키고 있는지 알 수 있습니다.
  • 참고로 기본형과 참조형간의 비교 연산은 서로서로 형변환이 불가능하기에 비교 할 수 없습니다.
  • 종종 대입연산자 ‘=’ 과 비교연산자 ‘==’을 헷갈리시는 분들이 있는데, 둘은 하는 역할이 완전히 다르기에 구별해서 사용해야합니다.
  • 아래의 예제를 통해 쉽게 이해가능합니다.
public class OperatorEx21 {
    public static void main(String[] args) {
        System.out.printf("10 == 10.0f \t %b \n", 10 == 10.0f);
        System.out.printf("'0' == 0 \t %b \n", '0' == 0);
        System.out.printf("'A' > 'B' \t %b \n", 'A' > 'B');
        System.out.printf("'A' + 1 == 'B' \t %b \n", 'A' + 1 == 'B');
    }
}

문자열의 비교

  • 두 문자열을 서로 비교할 경우, 비교 연산자 ‘==’ 대신 String 내부 메서드인 equals()를 사용해야합니다.
  • 해당 내용에 대한 포스팅도 존재하지만, 좀 더 상세하게 설명해보겠습니다.
  • 우선적으로 == 비교의 경우, Primitive Type에 대해서는 내부에 저장된 값 비교, Reference Type에 대해서는 가르키고 있는 주소값의 비교를 진행합니다.만약 방금 설명이 이해가 안가신다면, 기본형과 참조형의 차이를 공부하시는 것을 추천드립니다.
  • 결과적으로 Reference Type인 String의 경우에도 == 비교를 사용하면 해당 변수가 참조하고 있는 주소값의 비교를 수행하기에 String 내부의 문자열 값 비교는 수행하지 못합니다.그렇기에 String 내부 메서드인 equals()를 사용해서 문자열간의 비교를 진행해주면 됩니다.
  • String의 문자열 값 저장 방식에 대해서도 포스팅 할 내용이 많지만, 이후 포스팅에서 다루도록 하겠습니다. 지금은 아래 예제를 통해 동일한 문자열을 초기화 했지만, 참조하는 주소값이 다른 경우가 있다라는 것만 보여드리겠습니다.
public class OperatorEx23 {
    public static void main(String[] args) {
        String s1 = "hong"; // String internal => String Pool에 "hong" 저장한다.
        String s2 = "hong";
        String s3 = new String("hong"); // Heap 영역에 저장

        System.out.println("s1 = " + s1);
        System.out.println("s2 = " + s2);
        System.out.printf("s1 == s2의 비교 결과 : %b" , s1 == s2);
		System.out.println();
        System.out.printf("s1 == s3의 비교 결과 : %b" , s1 == s3);
    }
}

논리 연산자

  • 논리연산자는 둘 이상의 조건을 ‘그리고(AND)’나 ‘또는(OR)’으로 연결하여 하나의 식으로 표현 할 수 있게 해줍니다.
  • OR의 경우 ||로 표현하며 좌,우 피연산자 중 어느 한쪽만 true값이여도 true를 반환값으로 가집니다.
  • AND의 경우 &&로 표현하며 좌,우 피연산자 중 모두 true값이여만 true를 반환값으로 가집니다.
  • 예제를 통해 알아봅시다.반드시 작성한 코드를 컴파일 하기 전에 예측을 해보고 하는 습관을 들여야합니다.
public class OperatorEx24 {
    public static void main(String[] args) {
        int x = 0;
        char ch = ' ';

        x = 15;
        System.out.printf("x=%d, 10 < x && x < 20 = %b \n",x , 10 < x && x < 20);
        x = 6;
        System.out.printf("x=%d, x%%2==0 || x%%3==0 && x%%6!=0 = %b \n", x , x%2==0 || x%3==0 && x%6!=0);
        System.out.printf("x=%d, x%%2==0 || x%%3==0 && x%%6!=0 = %b \n", x , (x%2==0||x%3==0)&&x%6!=0);

        ch = '1';
        System.out.printf("ch='%c','0' <= ch && ch <= '9' = %b \n", ch , '0' <= ch && ch <= '9');

        ch = 'a';
        System.out.printf("ch='%c','a' <= ch && ch <= 'z' = %b \n", ch , 'a' <= ch && ch <= 'z');

        ch = 'A';
        System.out.printf("ch='%c','A' <= ch && ch <= 'Z' = %b \n", ch , 'A' <= ch && ch <= 'Z');
    }
}
  • 아래 예제를 통해서 Scanner를 통해 키보드로 변수의 값을 입력받고, 해당 변수가 숫자인지 대문자인지 소문자인지 판단하는 프로그램을 만들어봅시다.
public class OperatorEx25 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        char ch = ' ';

        System.out.print("문자를 하나 입력하세요 : ");
        String input = sc.nextLine();
        ch = input.charAt(0);

        if('0' < ch && ch <='9') {
            System.out.println("입력한 문자는 숫자입니다.");
            System.out.println("ch = " + ch);
        } else if (('a' <= ch && ch <= 'z')) {
            System.out.println("입력한 문자는 소문자입니다.");
            System.out.println("ch = " + ch);
        } else if (('A' <= ch && ch <= 'Z')) {
            System.out.println("입력한 문자는 대문자입니다.");
            System.out.println("ch = " + ch);
        }
    }
}

Short Circuit Evaluation(효율적인 연산)

  • OR연산에서 왼쪽의 피연산자가 참일 경우, 해당 OR 연산의 결과는 참입니다.
  • 그러면 오른쪽 피연산자를 계산하지도 않고 결과를 도출 할 수 있습니다.
  • 이러한 연산을 효율적인 연산이라고 합니다.생각해보면 당연하거니 이해하기 쉬울 것 입니다.
  • 이와 반대로 AND의 경우를 봅시다. AND 연산자의 왼쪽 피연산자가 false일 경우에는 오른쪽 피연산자를 계산하지 않아도 해당 연산자의 결과가 false라는 것을 도출 할 수 있습니다.
  • 아래 예제를 통해 명확하게 이해가능합니다. Short Circuit Eval를 진행했기에 b의 값이 끝까지 증가되지 않음을 이해하면 됩니다.
public class OperatorEx26 {
    public static void main(String[] args) {
        int a = 5;
        int b = 0;

        System.out.printf("a=%d, b=%d \n",a,b);
        System.out.printf("a != 0 || ++b!=0 = %b \n", a != 0 || ++b!=0);
        System.out.printf("a=%d, b=%d \n",a,b);
        System.out.printf("a == 0 && ++b!=0 = %b \n", a == 0 && ++b!=0);
        System.out.printf("a=%d, b=%d \n",a,b);
    }
}

논리 부정 연산자 !

  • 영문법에서 not과 동일한 기능 수행합니다.즉, 어떠한 조건에 대해서 참과 거짓을 반복적으로 도출시킬 수 있는 연산자입니다.
  • 아래의 예제를 통해 간단히 이해 할 수 있습니다.
public class OperatorEx27 {
    public static void main(String[] args) {
        boolean b = true;
        char ch = 'C';

        System.out.printf("b=%b\n", b);
        System.out.printf("!b=%b\n", !b);
        System.out.printf("!!b=%b\n", !!b);
        System.out.println();

        System.out.printf("ch=%c\n", ch);
        System.out.printf("ch <= 'a' || ch >= 'z' = %b \n", ch <= 'a' || ch >= 'z');
        System.out.printf("!(ch > 'a' || ch < 'z') = %b \n", !(ch > 'a' && ch < 'z'));
    }
}

비트 연산자

  • 비트 연산자는 피연산자를 비트단위로 논리 연산합니다. 피연산자를 이진수로 표현한 경우 각 자리를 아래의 규칙에 맞게 연산을 수행합니다.또한 피연산자는 오직 정수만 가능합니다.
  • “|” : 피연산자 중 한쪽의 값이 1이면 1을 결과로 얻는다.
  • “&” : 피연산자 중 양쪽 모두 1일 경우에만 1을 결과로 얻는다.
  • “^” : 피연산자의 값이 서로 다를 경우에만 1을 결과로 얻는다.
  • 아래는 연산 예시입니다.
  • 실제 코드로 해당 연산을 수행하는 것을 볼 수 있습니다. toBinaryString를 메서드로 새롭게 정의하여 사용했는데, 이는 2진수 앞에 사용자가보기 편하게 0을 채워넣기 위해서입니다.
public class OperatorEx28 {
    public static void main(String[] args) {
        int x = 0xAB, y = 0xF;
        System.out.printf("x = %#X \t\t\t%s \n", x, toBinaryString(x));
        System.out.printf("y = %#X \t\t\t%s \n", x, toBinaryString(y));
        System.out.printf("%#X | %#X = %#X \t%s \n", x,y,x | y, toBinaryString(x|y));
        System.out.printf("%#X & %#X = %#X \t%s \n", x,y,x & y, toBinaryString(x&y));
        System.out.printf("%#X ^ %#X = %#X \t%s \n", x,y,x ^ y, toBinaryString(x^y));
    }

    static String toBinaryString(int x) {
        String zero = "00000000000000000000000000000000";
        String tmp = zero + Integer.toBinaryString(x);
        return tmp.substring(tmp.length() - 32);
    }
}

삼항 연산자

  • 연산자 1편에서 삼항 연산자에 대한 언급이 한번 있었습니다.간단한 if문을 종종 삼항 연산자로 표현하니 알아두면 도움이 됩니다.
  • 해당 연산자는 모두 세개의 피연산자를 필요로 합니다.한개의 조건식과 두개의 나머지 실행될 수 있는 식으로 구성됩니다.
  • 아래 예제를 실행시켜보시면 직관적으로 이해가 갑니다.
public class OperatorEx32 {
    public static void main(String[] args) {
        int x,y,z;
        int absX,absY,absZ;

        x = 10;
        y = -5;
        z = 0;

        absX = x >= 0 ? x : -x;
        absY = y >= 0 ? x : -x;
        absZ = z >= 0 ? x : -x;

        System.out.println("absX = " + absX);
        System.out.println("absY = " + absY);
        System.out.println("absZ = " + absZ);
    }
}

Ref : 자바의정석 - 남궁성