자바(Java)

[자바] 자바 연산자

Ash_jisu 2023. 7. 29. 14:44

연산자(Operator)

- 연산을 수행하는 기호이다.

- 연산을 수행하기 위해선 대상, 바로 '피연산자'가 필요하다. 

연산자의 기능별 분류


산술 연산자

  • 산술연산자는 +, -, *, /, %로 이루어져있다.
  • 정수끼리 연산을 하면, 피연산자 중에 long이 있을경우에는 long으로 변환 후 수행, 그 외의 정수는 
    int로 변환된후 실행된다.

 

  • 산술 연산자의 오버플로우 
    • 오버플로우(Overflow)는 변수가 자신이 표현할 수 있는 범위를 벗어나는 값을 가지게 되는 상항을 말한다.
      연산자의 부분에서는 더하기나 곱하기등을 통해 표현할수있는 최대값을 벗어나면
      오버플로우가 발생한다.
public class Main {
    public static void main(String[] args) {
        int a = 1000000; // 1,000,000
        int b = 1000000;   // 1,000,000
        int result = a * b;

        System.out.println("곱셈 결과: " + result); //곱셈 결과: -727379968, 오버플로우 발생
    }
}
  • 부동 소수점 
    • 부동소수점은 실수를 표현하는 방식 중 하나이다.
      부동소수점은 이진법으로 표현할때 정확히 표현되지 않는 값들이 존재한다. 
      제대로 표현되는 값은 분모가 2의 거듭제곱을 사용하는 0.5(2분의1), 0.25(4분의 1), 0.125(8분의 1)
      과 같고 나머지는 정확히 표현할수가 없어 무한소수가 되어 근사치로 표현된다.
      아래 코드를 보면 0.3이 아니라 0.3......4 가 나오게 된다.
public class Main {
    public static void main(String[] args) {
        double num1 = 0.1;
        double num2 = 0.2;
        double result = num1 + num2;

        System.out.println("결과: " + result); // 예상: 0.3, 실제: 0.30000000000000004
    }
}

            따라서 이것을 해결할려면 'BigDecimal'과 같은 클래스를 사용하여 정확한 실수 연산을 해야한다.

 

 


비트 연산자

  • 비트 연산자는 말 그대로 비트 단위로 연산이 이루어지는 연산자이다. 
    데이터가 컴퓨터 내부에서 0과 1로 이루어져있기때문에 비트연산자라고 부른다. 그만큼 빠른 속도로 계산한다.
  • 비트 연산자는 &, |, ^, ~, <<, >>, >>> 등으로 이루어져있다. 
  • I(OR연산자) : 피연산자 중 한 쪽의 값이 1이면, 1을 결과로 얻는다.
  • &(AND연산자): 피연산자 양 쪽의 값이 모두 1이어야만 1을 결과로 얻는다.
  • ^(XOR연산자): 피연산자의 값이 서로 다를때만 1을 결과로 얻는다.
  • ~(비트 전환 연산자): 비트 값을 0은 1로, 1은 0으로 바꾸는 연산자이다.
 int num = 5;
 int result = ~num;
 System.out.println(result);  //-6이 출력이 된다.
 
 //num =  00000101
 //~num = 11111010

 

  • << >> 시프트 연산자의 의미는 다음과 같다.
    • << 왼쪽 시프트 연산자 경우: 피연산자의 비트를 왼쪽으로 이동시킨다.
    • >>오른쪽 시프트 연산자 경우: 피연산자의 비트를 오른쪽으로 이동시키는 연산을 수행한다.
    • 사용예시,   00101 -> 0010100  가 된다. 따라서 5->20
public class LeftShiftExample {
    public static void main(String[] args) {
        int num = 5; // 5는 이진수로 00000101 
        int result = num << 2; //왼쪽으로 2비트 이동

        System.out.println("원래 값: " + num); // 5
        System.out.println("시프트 결과: " + result); // 20 (00010100)
    }
}

 

 


관계 연산자

  • 비교 연산자라고도 하며 결과는 true 혹은 false, boolean 자료형으로 반환된다.
    아래는 관계연산자의 종류이다.

보통 조건절로 사용할때 많이 쓰인다고 생각하면 된다.

 

 


논리 연산자

  • 논리 연산자도 연산 결과가 true 혹은 false, boolean형으로 반환된다.
  • 논리 연산자는 AND(&&), OR(||), NOT(!) 세가지가 있다.
    아래는 대입연산자 종류와 기능이다.

예시 코드를 들면 다음과 같다.

        System.out.println(5>3);  //true    관계 연산자
        System.out.println(5>3&&5>4); //true    두 항 모두 다 참이므로 true
        System.out.println(5>3&&5>10);  //false   두 항중 오른쪽 항이 거짓이므로 false
        System.out.println(5>3||5>10);   //true   두 항중 오른쪽 항이 참이므로 false
        
        //조건문에서 논리연산자를 여러번 사용할경우 앞쪽에서 이미 false가 뜨면 뒤에 논리는 보지않는다.
        //활용가능한 부분: bfs 같은 너비탐색에서 상하좌우 노드 탐색하는경우 visited[i][j] 가 i가 음수로 범위를 벗어나는 오류 뜰수있으나 앞에가 false면 짤린다.
        if(i>=0&&i<N&&j>=0&&j<N&&visited[i][j])  //이미 i나 j에 음수가 들어가거나 범위 밖을 넘어가면 조건문이 종료된다.
  • 추가로 설명할 부분은 논리연산자중 &&, ||는 왼쪽부터 참인지 거짓인지 판단하게 되는데 &&왼쪽이 거짓이경우 오른쪽 항을 보지도 않고 false로 리턴한다. ||의 경우도 왼쪽이 참일경우 오른쪽항 판단하지않고 true로 리턴한다. 그래서 
    위에 코드 마지막 부분처럼 사용이 가능하다. 
    •  '||'와 '|'의 다른점은 |는 왼쪽항의 결과와 상관없이 오른쪽 항도 체크를 한다는것이다. 물론 그만큼 시간적으로는 더 걸리는게 사실이나 2개를 다 확실히 체크할 일이 있을경우에는 '|'쓰는것이 좋다.

 

 


instanceof

  • 객체 타입을 확인하는 연산자이다.
  • 형변환 가능여부를 확인하며 true/false로 결과를 반환한다.
  • 주로 상속 관계에서 부모객체인지 자식 객체인지 확인하는데 사용된다.
    밑에 코드를 통해 더 자세히 설명하겠다.
class Parent{}
class Child extends Parent{}

public class Main {
    public static void main(String[] args){
        Parent parent = new Parent();
        Child child = new Child();

        System.out.println( parent instanceof Parent );  // true, 부모가 부모클래스 소속이므로 true
        System.out.println( child instanceof Parent );   // true, 자식은 부모클래스로부터 상속받은 자식클래스 소속이므로 true
        System.out.println( parent instanceof Child );   // false, 자식이 부모로부터 상속받은거지 상속한게 아니므로 false
        System.out.println( child instanceof Child );   // true, 자식은 자식클래스로부터 나온것이므로 true
    }

}

 

 

 

 


assignment(=) operator

  • 대입연산자라고 하며 변수에 값을 대입할때 사용하는 이항 연산자이다.
  • 피연산자들의 결합 방향은 오른쪽에서 왼쪽이다.
  • 대입연산자의 종류

  • 예시 코드 작성

        int num1 = 10;
        int num2 = 5;
        num1 += num2; //15
        num1 -= num2; //5
        num1 *= num2; //50
        num1 /= num2; //2
        num1 %= num2; //0
        num1 <<= 2;  //40
        num1 &= 10;   //1

 

 

 


화살표(->) 연산자

  • 자바 8에서 람다 표현식이 추가됨에 따라 등장한 연산자이다.
  • 아래 예시를 통해 나타내보겠다.
    자바 8 이전의 인터페이스와 구현 클래스
// 인터페이스 선언
interface MyInterface {
    void doSomething();
}

// 인터페이스를 구현하는 클래스
class MyClass implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("Doing something in MyClass.");
    }
}

 

화살표 연산자와 람다식을 활용한 구현(메인에서 바로 구현후 사용)

// 함수형 인터페이스 선언
interface MyFunctionalInterface {
    void doSomething();
}

public class Main {
    public static void main(String[] args) {
        // 람다 표현식과 화살표 연산자를 활용한 메서드 구현
        MyFunctionalInterface myFunc = () -> System.out.println("Doing something with Lambda.");
        
        //메서드 호출
        myFunc.doSomething();
    }
}

근데 이제 MyFunctionalInerface가 반드시 단 하나의 메서드를 가져야만 사용할 수 있다. 아니면 어떤 메서드를
호출하는지를 알 수가 없다.

 

 


3항 연산자

  • 삼항 연산자는 세개의 피연산자를 통해 If문을 간략하게 처리한다.
    코드로 예시를 들겠다.  10>5가 성립하면 num = 10; 아니면 num = 5가된다는 가정으로 코드를 짜봤다.
         원래의 if문
int num;
if(10>5)num = 10;
else num = 5;

           삼항 연산자 사용

     int num = (10>5)?10:5;    //int num = (조건)? 조건true일시 발동: 조건 false일시 발동;
  • 삼항 연산자가 식을 간략하게 해주지만 계산속도가 빨라지는 것은 아니다.

 


연산자 우선 순위

  • 식에 여러개의 연산자가 있는 경우 우선순우가 높은 연산자를 먼저 처리한다.
  • 우선순위가 동일하면 왼쪽에서 오른쪽으로 순서대로 처리한다.

 

 

 


Java 13. switch 연산자

  • 13에 swtich 연산자 기능이 추가 되기전
    • 다수의 case,break 존재
    • break; 를 빼먹을 경우 다음분기로 넘어간다
    • return값이 존재할 수 없다.
  • 13에 switch 연산자 기능이 추가 되고난 후(변경이 아니다, 기존 switch문에 기능이 추가된거다)
    • break 대신 yield사용(return값 존재)
    • case -> A 같은 형식으로 표현가능
    • case가 모든 인자를 커버하는 경우 default 항목을 넣어주지 않아도 되나 그렇지 않은 경우는 default -> code를 작성해야한다.

기존 방식

        char c = 'B';
        int grade = 0;
        switch (c){
            case 'A':
                grade = 4;
                break;
            case 'B':
                grade = 3;
                break;
            case 'C':
                grade = 2;
                break;
            case 'D':
                grade = 1;
                break;
        }

 

 

Java 13 에서 나온 기능 활용 표현식

 

        char c = 'B';

        int grade = switch (c){
            case 'A': yield 4;
            case 'B': yield 3;
            case 'C': yield 2;
            case 'D': yield 1;
            default : throw new IllegalStateException("Invalid grade: " + c);
        }

 

 ※참고로 예약어는 변수명으로 사용불가능하지만 yield는 예외이다. 예약어로 사용가능하다.

 

 


참고