자바생
article thumbnail
Published 2022. 5. 6. 20:42
java 연산자 Java
728x90

산술 연산자(Arithmetic Operators)

  • 간단한 수학 연산을 하기 위해 사용하는 연산자
  • 기본 숫자 및 그에 대응하는 boxed type에서만 작동
  • +, -, *, /, %가 존재한다
    • '/'는 몫, '%'는 나머지를 의미한다
@Test
@DisplayName("산술 연산")
void op() throws Exception{
    int a = 6;
    int b = 4;

    System.out.println("a/b = " + a / b); //몫
    System.out.println("a%b = " + a % b); //나머지
}

비트 연산자(Bitwise Operators)

  • 비트 연산자에는 Bitwise Logical Operators, Bitwise Shift Operators로 나눌 수 있다

 

Bitwise Logical Operators

  • AND, OR, XOR, Complement Operator 가 있다

 

Complement 연산

b는 현재 0000 0110 이고, ~b는 1111 1001

최고 비트가 1이므로 b의 보수는 음수를 의미한다

따라서 음수인 수는 그 수의 보수를 구하여 다시 10진수로 변환해야 한다

 

따라서 1111 1001의 2의 보수는 0000 0110 + 1 이므로 0000 0111

즉, -7이 된다~

 

Bitwise Shift Operators

  • Signed Left/Right Shift, Unsigned Right Shift가 있다

 

Signed Left Shift

  • 변수 << [이동 횟수]
  • 이동 횟수만큼 비트를 왼쪽으로 이동
  • 오른쪽의 빈 공간은 0으로 채워짐
  • 즉, 왼쪽으로 n번 움직이는 것은 2^n을 곱한 것과 같다
@Test
@DisplayName("비트 leftshift")
void shift() throws Exception{
    int x = 12;
    System.out.println("12를 2진수 = " + Integer.toBinaryString(x)); //1100
    
    int leftShift = x << 2;
    System.out.println("leftShift = " + leftShift); //48

    x = -12;

    leftShift = x << 2;
    System.out.println("leftShift = " + leftShift); //-48
}

 

Signed Right Shift

  • left shift와 형식은 비슷하지만 방향만 다르다
  • 이동횟수만큼 비트를 오른쪽으로 이동
  • 변수가 음수일 때(가장 왼쪽 비트 1), 빈 공간은 1로 채워짐
  • 변수가 양수일 때(가장 왼쪽 비트 0), 빈 공간은 0으로 채워짐
@Test
@DisplayName("비트 right_shift")
void right_shift() throws Exception{
    int x = 12;
    System.out.println("12를 2진수 = " + Integer.toBinaryString(x)); //1100

    int right_shift = x >> 2;
    System.out.println("right_shift = " + right_shift); //3

    x = -12;

    right_shift = x >> 2;
    System.out.println("right_shift = " + right_shift); //-3
}

 

Unsigned Right Shift

  • Signed Right Shift와 매우 유사
  • 다른 점은 숫자를 이동하고 난 뒤, 양수 음수 상관없이 0으로 채워짐
  • 따라서 결과는 항상 양의 정수가 나옴
@Test
@DisplayName("비트 unsigned_right_shift")
void unsigned_right_shift() throws Exception{
    int x = 12;
    System.out.println("12를 2진수 = " + Integer.toBinaryString(x)); //1100

    int unsigned_right_shift = x >>> 2;
    System.out.println("unsigned_right_shift = " + unsigned_right_shift); //3

    x = -12;

    unsigned_right_shift = x >>> 2;
    System.out.println("unsigned_right_shift = " + unsigned_right_shift); //1073741821
}

 

관계 연산자(Relational Operators)

  • 관계 연산자는 "비교 연산자(Comparison operators)"라고도 한다
  • ==, !=, >, >=, <, <= 가 있지만 우리는 ==을 유심히 봐보자

Java에서 비교를 할 시, ==와 equals 중에 어떤 것을 사용해야 할까?라는 의문이 들 수 있다

나는 대부분 값을 비교할 시 ==을 사용하고, 객체를 비교할 시 무조건 equals를 사용한다

 

각 숫자에 대응되는 wrapper class들(interget ...)도 equals를 사용한다

  • Integer를 비교할 때 ==을 사용 시 -128~127까지는 올바르게 비교 값이 나오지만 그 이후에는 예상치 못한 결괏값이 나올 수 있다
  • 해당 부분은 "IntegerCache"를 참고하면 알 수 있다
@Test
@DisplayName("Integer 비교")
void relational() throws Exception{
    Integer a = 129;
    Integer b = 129;

    Integer c = 124;
    Integer d = 124;

    System.out.println(a == b); //false
    System.out.println(c == d); //true

    System.out.println(a.equals(b)); //true
    System.out.println(c.equals(d)); //true
}

 

논리 연산자(Logical Operators)

  • java에서 제공되는 논리 연산자에는 AND, OR 연산자가 있다
  • &&와 || 로 표현

 

||(OR) 연산자 특징

  • 만약 이 앞의 조건이 참이라면 뒤의 연산을 계산하지 않고 true를 반환한다
@Test
@DisplayName("|| 특징")
void logical() throws Exception{
    int a = 4;
    int b = 5;

    if (a >= 4 || ++b > 5) {
        System.out.println("b = " + b); //b의 값은 5
    }

    if (a >= 5 || ++b > 5) {
        System.out.println("b = " + b); //b의 값은 6
    }
}

 

instance of

참조 변수 instanceof 클래스

 

참조 변수가 "참조"하고 있는 "인스턴스"의 실제 타입을 알아보기 위해 사용한다

따라서 형 변환이 가능한지 검사하는 기능 또한 가지고 있다

 

static class A{}
static class B extends A{}
static class C extends A{}
    
@Test
@DisplayName("instance of")
void instance_of() throws Exception{
    A a = new A();

    System.out.println(a instanceof B); //f
    System.out.println(a instanceof C); //f

    a = new B();

    System.out.println(a instanceof A); //t
    System.out.println(a instanceof B); //t
    System.out.println(a instanceof C); //f
}

처음에 참조 변수 a는 A 클래스를 참조하고 있다

그래서 A 클래스는 B 클래스로 형 변환을 할 수 있을까에 대한 답은 NO다  C 또한 마찬가지

 

두 번째에서는 참조 변수 a는 B 클래스를 참조하고 있다

B 클래스는 A 클래스로 형 변환할 수 있을까에 대한 답은 YES다

 

B와 C는 아무런 관계가 없으므로 당연히 NO다

 

assignment operator(=)

= 연산은 primitive type과 reference type에 따라 의미가 달라진다

 

primitive에서 int a = 3; 을 하게 되면 우리는 a의 값에 3을 저장한다

 

reference type에서는 주소 값을 할당하는 것이다

/**
 * a = study.querydsl.QuerydslBasicTest$A@3f78a5ed
 * b = study.querydsl.QuerydslBasicTest$A@630e5010
 * a = study.querydsl.QuerydslBasicTest$A@630e5010
 * b = study.querydsl.QuerydslBasicTest$A@630e5010
 */
@Test
@DisplayName("reference type에서 = 연산")
void assignment() throws Exception{
    A a = new A();
    A b = new A();

    System.out.println("a = " + a);
    System.out.println("b = " + b);

    a = b;

    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

처음에는 a와 b가 주소값을 가지고 있었다

 

a = b의 연산을 하고 나서 a와 b 모두 b의 주소값을 참조하고 있게 된다

이 뜻은 a의 주소 값에 b의 주소 값을 저장한다 즉, a는 b가 참조하고 있는 주소 값을 참조한다 라는 뜻이다

 

reference type의 assignmnet operator는 주소값을 할당해주는 것을 알 수 있다

 

Compound Assignments

+=, -=, *=, /=, %= 을 compound assignment 라고 한다

 

a += b 의미는 a = a + b라는 뜻이다 

나머지 연산들도 모두 같은 말이다

 

 

화살표 연산자(->)

java 8에서 람다의 도입에 따라 화살표 연산자도 등장하게 됐다

 

이는 람다식을 배우게 되면 사용하게 되는 연산자이다

람다식 공부

 

3항 연산자(Ternary Operator)

  • if-else 문을 줄여주기 위해 사용되는 연산자
  • 조건 ? true일 경우 행동 : false일 경우 행동
@Test
@DisplayName("|| 특징")
void logical() throws Exception{
    int a = 4;

    String result1 = a >= 4 ? "참" : "거짓";
    String result2 = a > 4 ? "참" : "거짓";

    System.out.println("result1 = " + result1); //참
    System.out.println("result2 = " + result2); //거짓
}

 

 

연산자 우선순위

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

unary(단항) 연산자와 assignment 연산자는 <- 방향으로 진행, 나머지 연산들은 -> 방향으로 진행된다

 

산술 -> 비교 -> 논리 -> 대입 순서로 알 수 있다~

 

 

Java 13 switch 연산자

 

Java 12 전 switch 연산

@Test
void post12_switch() throws Exception{
    int a = 1;

    switch (a) {
        case 1:
            System.out.println("1");
            break;
        case 2:
            System.out.println("2");
            break;
        default:
            System.out.println("3");
            break;
    }
}

 

Java 12 이후 " - > " 사용

switch expression으로 사용할 수 있게 됐다

즉, 단일 값으로 평가되어 명령문에서도 사용할 수 있다

@Test
void switch_12() throws Exception {
    int a = 1;

    switch (a) {
        case 1 -> System.out.println("1");
        case 2 -> System.out.println("2");
        default -> System.out.println("many");
    }
}

여기에 이어서 인자로 사용할 수도 있게 됐다

@Test
void switch_12() throws Exception {
    int a = 1;

    System.out.println(
            switch (a) {
                case 1 -> 1;
                case 2 -> 2;
                default -> 3;
            }
    );
}

 

Java 13 yield

 

Java 13에서 인자로 사용할 수 있기 때문에 변수에도 할당할 수 있게 "yield"를 사용했다

switch statement는 break의 target, switch의 expression은 yield의 타겟이 될 수 있다

@Test
void switch_13() throws Exception {
    int num = 1;

    int numLetters = switch (num) {
        case 2 -> {
            System.out.println(7);
            yield 7;
        }
        case 7 -> {
            System.out.println(8);
            yield 8;
        }
        case 1 -> {
            System.out.println(1);
            yield 0;
        }
        default -> throw new IllegalStateException("Invalid num: " + num);
    };

    System.out.println("numLetters = " + numLetters);

    /**
     * 1
     * numLetters = 0
     */
}

현재 num 값은 1이므로 case 1에 걸리게 되고 1을 출력하게 된다.

여기서 yield 0을 하게 되면 0을 반환하고, numLetters에는 0이 저장된다

 

따라서 numLetters를 출력하면 0이 출력된다~


REFERENCES

switch Java 13(oracle)

연산자(baeldung)

비트 연산

728x90

'Java' 카테고리의 다른 글

정적 메서드는 왜 오버라이딩 되지 않을까?  (0) 2022.08.29
throw vs throws  (0) 2022.05.17
Primitive Type, Reference Type, Literal  (0) 2022.05.03
Java volatile keyword  (0) 2022.04.18
final 키워드  (0) 2022.03.05
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그