신규 블로그를 만들었습니다!

2020년 이후부터는 아래 블로그에서 활동합니다.

댓글로 질문 주셔도 확인하기 어려울 수 있습니다.

>> https://bluemiv.tistory.com/

1.연산자

1.1. 연산자와 피연산자

연산자(operator): 연산을 수행하는 기호 (+, -, *, /)

피연산자(operand): 연산자의 작업 대상(변수, 상수, 리터럴, 수식)

1.2. 연산자의 종류

  • 산술 연산자: +, -, *, /, %, <<, >>
  • 비교 연산자: >, <, >=, <=, !=, ==
  • 논리 연산자: &&, ||, !, &, |, ^(xor), ~(not)
  • 대입 연산자: =
  • 삼항 연산자: x ? y : z

1.3. 연산자의 우선순위와 결합규칙

  • 단항 연산자가 이항 연산자보다 우선순위가 높다 (단항 > 이항)
  • 비교 연산자가 산술 연산자보다 우선순위가 높다 (비교 > 산술)
  • 논리 연산자보다 비교 연산자보다 우선순위가 높다 (논리 > 비교)
  • 비교 연산자가 비트 연산자보다 우선순위가 높다. (비교 > 비트)
  • 덧셈 연산자는 쉬프트 연산자보다 우선순위가 높다. (덧셈 > 쉬프트)
  • 대입 연산자가 연산자 중 우선순위가 제일 높다

1.4. 산술 변환 (user arithmetic conversion)

이항 연산자의 경우는 타입을 일치시켜야 연산이 가능하다.

int i = 10;
float f = 20.0f;
float result = f + (float) i; // 캐스팅을 통해 타입을 일치

대부분의 경우, 범위가 큰 타입으로 캐스팅을 한다. (값 손실을 막기위해) 이렇게 작은 범위 값을 큰 범위값으로 캐스팅 하는 경우 자동적으로 해주기 때문에, 생략이 가능하다.

 

산술 변환의 규칙

  • 범위가 큰 타입으로 캐스팅 한다.
  • 피연산자의 타입이 int보다 작은 경우 int로 변환된다.
byte b = 20;
short s = 10;
Object result = b + s;
System.out.println(result.getClass().getName()); // java.lang.Integer

int보다 작은 타입은 연산시 int 타입으로 캐스팅되는 이유는 int가 값을 자장 효율적으로 처리 할 수 있기 때문이다.

2. 단항 연산자

2.1. 증감 연산자 ++, --

증감 연산자

  • 증가 연산자 (++): 값 1 증가
  • 감소 연산자 (--): 값 1 감소

전/후위형

  • 전위형: 값이 참조되기 전에 값을 연산한다. (j = ++i;)
  • 후위형: 값이 참조된 후 값을 연산한다. (j = i++;)
int i = 5;
System.out.println(++i); // 6

i = 5;
System.out.println(i++); // 5
System.out.println(i); // 6
// System.out.println(++i); 는 아래 코드와 같다.
i += 1;
System.out.println(i);

// System.out.println(i++); 는 아래 코드와 같다.
System.out.println(i);
i += 1;

가독성을 위해 하나의 식에서 증감연산자를 2개 이상 사용하는 것은 피하는 것이 좋다.

3. 산술 연산자

산술 연산자: +, -, *, /

3.1. 연산시 Overflow 주의

int i = 1000000;
// Overflow 발생하여 기대하던 1000000 값이 나오지 않고 -727이 나온다.
System.out.println(i * i / i); // -727
System.out.println(i * i); // -727379968

3.2. 문자 연산

문자 형태의 숫자를 정수로 변환하려면 문자 '0'을 빼주면된다.

  • 2의 아스키코드: 50
  • 0의 아스키코드: 48
System.out.println('2' - '0'); // '2' - '0' = 50 - 48 = 2

문자간의 연산도 가능하다. (char는 아스키코드(정수)를 저장하므로)

System.out.println('d' - 'a'); // 3

리터럴 간의 연산은 실행과정동안 변하는 값이 아니기 때문에, 컴파일러 코드를 효율적으로 만들면서 덧셈연산을 미리 해버린다.

char c1 = 'a';
//char c2 = c1 + 1; // 컴파일 에러. int의 타입 범위가 더 크기 때문에 int로 캐스팅이 됨
char c2 = (char) (c1 + 1); // char 로 형변환이 필요함
char c3 = 'a' + 1; // 리터럴 연산이기 때문에, 에러 발생하지 않음.

즉 컴팡일러를 통해 코드는 아래와 같이 변화된다.

// 컴파일 전의 코드
char c = 'a' + 1;
// 컴파일 후의 코드
char c = 'b';

4. 비교 연산자

문자열을 비교할때는 ==가 아닌 equals()를 사용한다. String 은 클래스이기 때문이다.

String str1 = "ABCD";
String str2 = new String("ABCD");
System.out.println(str1 == str2); // flase
System.out.println(str1.equals(str2)); // true

클래스를 == 연산자로 비교를 하게되면 주소값을 비교하기 때문에 위와 같은 결과가 나온다. 그래서 문자열이 같은지 확인하기 위해서는 String 클래스에서 제공해주는 .equals() 메소드를 사용해야 한다.

대소문자 상관없이 비교할때는 equalsIgnoreCase()를 사용한다.

5. 논리 연산자

5.1. 효율적인 연산(short circuit evalution)

논리 연산을 할때 좌측부터 우측으로 연산한다. 연산중에 좌측에서 이미 결과가 나와버리는 경우 우측은 평가하지 않는다.

예를들어, OR의 경우 좌측이 true이면 무조건 결과는 true이다. AND의 경우 좌측이 false이면 무조건 false 이다.

참고. 예상된 결과가 확률적으로 높게 나오는 평가 식을 좌측에 두는 것이 좋다. (그래야 우측을 평가할 필요가 없어지므로 효율적이다)

5.2. 쉬프트 연산

쉬프트 연산이 빠르긴 하지만 가독성이 떨어지므로 곱셈이나 나눗셈을 이용하는 것이 좋다. 만일 빠른 속도를 요구하는 경우엔 쉬프트 연산을 이용한다.

Reference

Java의 정석, 남궁 성 지음

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기