일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- geometry
- Tree
- Number Theory
- two pointers
- 파이썬
- Binary Search
- database
- SQL
- dynamic programming
- string
- bit manipulation
- array
- 구현
- Math
- Binary Tree
- Method
- Data Structure
- simulation
- 자바
- Class
- greedy
- Stack
- sorting
- Counting
- hash table
- implement
- java
- 코딩테스트
- 코테
- Matrix
- Today
- Total
코린이의 소소한 공부노트
연산자(operator)의 종류와 우선순위, 결합규칙 본문
연산자는 우리가 익히 알고 있는 +, -같이 연산을 하는 기호를 말한다. 그리고 연산자와 함께 쓰이는 숫자, 변수 등 연산자의 연산 대상을 피연산자라고 한다. 수학 시간에 계산하고 나면 꼭 답이 나왔듯, 모든 연산자는 연산 결과를 반환한다. 연산 과정에서 쓰이는 괄호 ( ), { }, [ ] 는 연산 순서를 나타낼 뿐 결과가 나오는 것이 아니므로 연산자가 아니다.
int x = 3;
int y;
y = 5 * x - 6;
int 변수 x, y 2가지를 선언했다. 저 표현식(expression)이 당연하게 받아들여지긴 하지만 그래도 설명해본다면,
1) 메모리에 정수형 기억공간이 하나 생기고, x라는 이름이 붙고, 3이라는 값이 저장되었다.
2) 메모리에 정수형 기억공간이 하나 생기고, y라는 이름이 붙고, 아직 초기화 전이다.
3) 5 * x를 먼저 계산한다. x 자리에 x의 값인 3을 불러와 계산해서 15가 되었다.
4) 15 - 6을 계산하여 9가 나왔고, 이를 y에 대입한다.
우리에게 익숙한 연산 순서이고, 결과이다. 이 글에서 설명할 다른 연산자들도 마찬가지다. 처음 보는 것 같아도 우리에게 이미 익숙하고, 상식적인 선에서 받아들일 수 있다.
자바에서 쓰이는 연산자들은 다음과 같다.
1. 산술 연산자
1) + 더하기
System.out.println(11 + 3); // 14
System.out.println("11" + "3"); // "113"
- 이항 연산자
- 두 피연산자의 덧셈 결과를 반환한다.
- 피연산자가 문자열일 경우 두 문자열을 붙인다.
2) - 빼기
System.out.println(11 - 3); // 8
- 이항 연산자
- 두 피연산자의 뺄셈 결과를 반환한다.
3) * 곱하기
System.out.println(11 * 3); // 33
- 이항 연산자
- 두 피연산자의 곱셈 결과를 반환한다.
4) / 나누기
System.out.println(11 / 3); // 3
System.out.println(11.0 / 3); // 3.666...
System.out.println(12 / 3); // 4
- 이항 연산자
- 두 피연산자의 나눗셈 결과를 반환한다.
- 정수 간의 나눗셈의 경우, 나눈 몫을 반환한다.
5) % 나머지(mod)
System.out.println(11 % 3); // 2
System.out.println(12 % 3); // 0
// 나누기 연산에 음수가 섞여있을 때
// 몫과 나머지에 생기는 일
// (+) 나누기 (+)
System.out.println(10 / 8); // 1
System.out.println(10 % 8); // 2
// 10 = 8 * 1 + 2
// (+) 나누기 (-)
System.out.println(10 / -8); // -1
System.out.println(10 % -8); // 2
// 10 = (-8) * (-1) + 2
// (-) 나누기 (+)
System.out.println(-10 / 8); // -1
System.out.println(-10 % 8); // -2
// -10 = 8 * (-1) + (-2)
// (-) 나누기 (-)
System.out.println(-10 / -8); // 1
System.out.println(-10 % -8); // -2
// -10 = (-8) * 1 + (-2)
- 이항 연산자
- 왼쪽 피연산자를 오른쪽 피연산자로 나눴을 때의 나머지를 반환한다.
- 이때 오른쪽 피연산자는 0이 아닌 정수만 허용한다.
- 나머지 연산의 결과는 두 피연산자의 부호는 무시하고 계산한 후 왼쪽 피연산자의 부호를 붙이면 된다.
6) 비트 연산자 << 왼쪽 쉬프트(shift), >> 오른쪽 쉬프트
- 이항 연산자
- 이진수를 왼쪽/오른쪽으로 민 결과를 반환한다.
- 왼쪽으로 밀고 난 공간은 부호비트(양수는 0, 음수는 1)로 채운다.
- 오른쪽으로 밀고 난 공간은 0으로 채운다.
2. 비교 연산자
1) >, < 크다(초과), 작다(미만)
System.out.println(5 > 7); // false
System.out.println(5 < 7); // true
- 이항 연산자
- 왼쪽 피연산자가 오른쪽 피연산자보다 큰지/작은지 비교하여 결과를 반환한다.
2) >=, <= 크거나 같다(이상), 작거나 같다(이하)
System.out.println(5 >= 7); //false
System.out.println(5 <= 7); // true
- 이항 연산자
- 왼쪽 피연산자가 오른쪽 피연산자 이상인지/이하인지 비교하여 결과를 반환한다.
3) ==, != 같다, 다르다
System.out.println(5 == 7); // false
System.out.println(5 != 7); // true
- 이항 연산자
- 두 피연산자의 같음/다름을 비교하여 결과를 반환한다.
3. 논리 연산자
1) && 그리고(AND)
System.out.println( (4 > 7) && (5 < 7) ); // F AND T = false
- 이항 연산자
- 두 피연산자가 모두 참일 때 true, 나머지 경우는 false를 반환한다.
2) || 또는(OR)
System.out.println( (4 > 7) || (5 < 7) ); // F OR T = true
- 이항 연산자
- 두 피연산자가 모두 거짓일 때 false, 나머지 경우는 true를 반환한다.
- shift 키 + 엔터 위 \ = |
3) ! 아니다(NOT)
System.out.println( !(4 > 7) ); // NOT F = true
- 단항 연산자
- 피연산자의 반대 논리값을 반환한다.
4) 비트 연산자 & and, | or, ^ xor, ~ not
int x=5, y=9;
String x_bin = Integer.toBinaryString(x); // "0101"
String y_bin = Integer.toBinaryString(y); // "1001"
// int는 4 byte이지만 앞부분 28 bit가 다 0이라서 생략하고
// 맨 뒤 4 bit만 문자열로 표현한 것
비트 논리 연산은 피연산자를 오른쪽 정렬해서 1 비트씩 연산한다.
// 0101 and 1001 (둘 다 1일 때만 1)
System.out.println(Integer.toBinaryString(x & y)); // "0001"
// 0101 or 1001 (둘 다 0일 때만 0)
System.out.println(Integer.toBinaryString(x | y)); // "1101"
// 0101 xor 1001 (둘이 다른 값일 때 1)
System.out.println(Integer.toBinaryString(x ^ y)); // "1100"
// not 0101 (0은 1로, 1은 0으로)
System.out.println(Integer.toBinaryString(~x)); // "1111 1111 1111 1111 1111 1111 1111 1010"
4. 대입 연산자
1) = 등호
int a = 3;
int b = a + 4; // 7
- 이항 연산자
- 우변을 계산한 후 좌변에 대입한다.
2) 줄여 쓰는 대입 연산자
// x=9일 때 각 경우에 벌어지는 일
x += 1; // 10
x -= 1; // 8
x *= 2; // 18
x /= 3; // 3
x %= 2; // 1
// 기타 사용 가능한 대입 연산자
// <<= >>= &= ^= |=
- 이항 연산자
- 우변을 계산한 후 좌변에 대입한다.
5. 기타 연산자
1) (타입) 형변환
2021.12.29 - [Java] - 형변환(type casting)
2) ?: 3항 연산자
int x=5, y=9;
System.out.println( x>y ? 10 : 20 ); // 20
- 사용방법: 조건식 ? 참일 때 결과 : 거짓일 때 결과
- if문을 간단하게 표현하는 연산자
- 코드는 짧아지지만 컴파일 속도가 빨라지지는 않음
- 3항 연산자 중첩은 가독성을 떨어뜨림
3) instanceof 객체 연산자
System.out.println("HI" instanceof Object); // true
// "HI": 문자열이므로 String 클래스
// Object: 모든 클래스의 조상격인 클래스
- 이항 연산자
- 참조형 변수만 피연산자가 될 수 있다.
- 해당 객체가 주어진 클래스의 객체인지 확인한다. 맞으면 true, 아니면 false를 반환한다.
4) ++, -- 증감 연산자
int x=3, y=0;
// 전위형 증가 연산자
y = ++x;
System.out.println("x=" + x +", y="+ y); // x=4, y=4
// y = ++x; // 전위형은
// x = x+1; y = x; // 1 증가 후 대입하는 것
x=3; y=0;
// 후위형 증가 연산자
y = x++;
System.out.println("x=" + x +", y="+ y); // x=4, y=3
// y = x++; // 후위형은
// y = x; x = x+1; // 대입 후 1 증가하는 것
x++; // x=5
++x; // x=6
// -- 감소 연산자는 피연산자를 1 감소시킴
- 단항 연산자
- 증감 연산자가 독립적으로 쓰일 경우 전위형과 후위형의 차이는 없다.
5) +, - 부호 연산자
int i = -5;
System.out.println(+i); // -5
System.out.println(-i); // 5
- 단항 연산자
- 플러스(+): 변수에 + 부호를 붙임 -> 아무 변화 없음 -> 거의 사용 안 함
- 마이너스(-): 변수에 - 부호를 붙임 -> 부호가 반대로 바뀜
연산자에는 무엇이 있는지 봤으니, 이제 이 연산자들의 우선순위를 알아보겠다. 우선순위란 어떤 식에 연산자가 여러 개 있을 경우 어떤 연산을 먼저 수행할지 컴파일러가 자동으로 결정해주는 것을 말한다. 만약 수동 결정을 하고 싶다면 괄호를 활용하면 된다. 이는 우리가 수학 시간에 배운 것과 같다.
굳이 외우려고 하지 않아도 우리는 자연스럽게 이 우선순위를 받아들이고 이용하고 있다.
int x=16, y=3, z=-10;
// x가 4y+1보다 크고 -z가 20 이하일때 yes
// 아니라면 no 출력
String result = x>4*y+1 && -z<=20 ? "yes" : "no";
System.out.println(result); // yes
1) x > 4*y+1
- 4*y 계산 후 +1이 계산되어야 x값이랑 비교가 가능하고, 결과는 true이다.
- 곱셈은 덧셈보다 우선순위가 높다.
- 산술 연산자는 비교 연산자보다 우선순위가 높다.
2) -z <= 20
- 부호 연산자가 계산되어야 20이랑 비교가 가능하고, 결과는 true이다.
- 단항 연산자는 이항 연산자보다 우선순위가 높다.
3) x>4*y+1 && -z<=20
- 비교 연산이 끝나야 논리 연산을 할 수 있고, 결과는 true이다.
- 비교 연산자는 논리 연산자보다 우선순위가 높다.
4) x>4*y+1 && -z<=20 ? "yes" : "no"
- 조건식이 참이므로 "yes"가 선택된다.
- 이항 연산자는 삼항 연산자보다 우선순위가 높다.
5) String result = x>4*y+1 && -z<=20 ? "yes" : "no";
- 우변의 결과인 "yes"가 result에 대입된다.
- 대입 연산자는 우선순위가 가장 낮다.
컴파일러도 결국 사람이 만든 거라 사람이 이해하기 편한 방식으로 우선순위가 정해져 있기 때문에, 위의 코드를 해석하는 데 별 무리 없을 거라 생각한다. 만약 헷갈리는 우선순위가 있다면, 주저하지 말고 괄호를 이용하면 된다.
연산자의 우선순위로 익혔으니, 이제 연산자의 결합 규칙만 알면 된다. 연산자의 결합 규칙은 우선순위가 같은 연산자들이 여러 개 있을 때 연산 순위를 정해주는 규칙이다. 결론부터 말하자면 대입 연산자와 단항 연산자만 오른쪽에서 왼쪽(뒤에서부터)이고, 나머지는 전부 다 왼쪽에서 오른쪽(앞에서부터)으로 계산해주면 된다.
// 우선순위가 같은 산술 연산자
10 + 20 - 5 // 왼쪽 +부터 계산
-> 30 - 5 // 남은 - 계산
-> 25
// 대입 연산자는 오른쪽부터 계산
x = y = 7 // y에 7이 먼저 저장됨
-> x = y // y의 값을 불러옴
-> x = 7 // x에 7이 저장됨
'Java' 카테고리의 다른 글
산술 연산자와 산술 변환 (0) | 2021.12.31 |
---|---|
형변환(type casting) (0) | 2021.12.29 |
정수의 오버플로우(overflow) (0) | 2021.12.16 |
Scanner를 이용해 값을 직접 입력해서 화면에 출력하기 (0) | 2021.12.12 |
printf()를 이용한 형식화된 출력 (0) | 2021.12.12 |