on
연산자 Operator 1편
연산자 Operator
이 글은 남궁성님의 자바의 정석 3/e을 기반으로 공부한 내용을 정리한 글입니다.
연산자(operator)
연산자는 연산을 수행하는 기호를 말한다.
1.1 연산자와 피연산자
연산자가 연산을 수행하는 대상을 피연산자(operand)라고 하며, 상수
, 변수
또는 식
등을 사용할 수 있다.
대부분의 연산자는 두 개의 피연산자를 필요로 하며, 하나 또는 세 개의 피연산자를 필요로 하는 연산자도 있다. 연산자는 피연산자로 연산을 수행하고 나면 항상 결과값을 반환한다.
1.2 식과 대입연산자
식
이란 연산자와 피연산자를 조합하여 계산하는 것을 표현한 것이다. 식
을 계산하여 결과를 얻는 것을 식을 평가(evaluation)한다.고 한다. 하나의 식을 평가(계산)하면, 하나의 결과를 얻는다. 작성된 식을 프로그램에 포함시키려면, 식 끝에 ;
을 붙여 문장으로 만들어야 한다.
식의 평가결과를 출력하기만 원하고 다른 곳에 사용하지 않을 것이라면 변수에 저장하지 않고 println 메서드의 괄호() 안에 직접 식을 써도 된다.
1.3 연산자의 종류
연산자는 크게 산술, 비교, 논리, 대입 4가지로 나눌 수 있다.
피연산자의 개수에 의한 분류
피연산자의 개수로 연산자를 분류하기도 하는데, 피연산자의 개수가 하나면 단항 연산자, 두 개면 이항 연산자, 세 개면 삼항 연산자라고 부른다. 대부분은 이항 연산자이고 삼항 연산자는 오직 ? :
하나 뿐이다.
연산자를 기능별, 피연산자의 개수별로 나누어 분류하는 것은 연산자의 우선순위때문이다.
1.4 연산자의 우선순위와 결합규칙
식에 사용된 연산자가 둘 이상인 경우, 연산자의 우선순위에 의해 연산순서가 결정된다. 대부분의 연산자는 상식적인 선에서 해결된다. 하지만 우선순위를 판단하기 쉽지 않은 경우가 종종 있으므로 괄호를 사용해서 우선순위를 명확히 하는 것이 좋다.
식 | 설명 |
x < -1 || x > 3 && x < 5 | 논리 연산자 중에서 AND를 의미하는 & 와&& 가 OR을 의미하는 | 와 || 보다 우선순위가 높다.x < -1 || ( x > 3 && x < 5 ) |
연산자의 결합규칙
우선순위가 같다고 해서 아무거나 먼저 처리하는 것이 아닌 나름의 규칙이 있는데 그 규칙을 연산자의 결합규칙이라고 한다.
연산자의 결합규칙은 연산자마다 다르지만, 대부분 왼쪽에서 오른쪽의 순서로 연산을 수행하고, 단항 연산자와 대입 연산자만 오른쪽에서 왼쪽으로 연산을 수행한다.
모든 연산자는 연산결과를 가지는데, 대입연산자도 예외는 아니다. 대입연산자는 우변의 값을 좌변에 저장하고, 저장된 값을 연산결과로 반환한다.
1. 산술 > 비교 > 논리 > 대입. 대입은 제일 마지막에 수행된다.
2. 단항(1) > 이항(2) > 삼항(3). 단항 연산자의 우선순위가 이항 연산자보다 높다.
3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.
1.5 산술 변환(usual arithmetic conversion)
연산 전에 피연산자 타입의 일치를 위해 자동 형변환되는 것을 산술 변환 또는 일반 산술 변환이라고 한다. 이 변환은 단항 연산에서도 일어난다.
산술 변환의 규칙은 다음과 같다.
- 두 피연산자의 타입을 같게 일치시킨다.(보다 큰 타입으로 일치)
long + int -> long + long -> long
float + int -> float + float -> float
double + float -> double + double -> double - 피연산자의 타입이 int보다 작은 타입이면 int로 변환된다.
byte + short -> int + int -> int
char + shotr -> int + int -> int
| 참고 | 모든 연산에서 ‘산술 변환’이 일어나지만, 쉬프트 연산자, 증감 연산자는 예외이다.
1번 규칙은 피연산자의 값손실을 최소화하기 위한 것이고, 2번 규칙은 정수형의 기본 타입인 int
가 가장 효율적으로 처리할 수 있는 타입이고 char
나 short
의 표현범위가 좁아서 연산 중 오버플로우가 발생할 가능성이 높기 때문에 만들어졌다.
연산결과의 타입은 피연산자의 타입과 일치한다.
단항 연산자
2.1 증감 연산자 ++ –
증감 연산자는 피연산자에 저장된 값을 1 증가 또는 감소시킨다. 피연산자로 정수와 실수가 모두 가능하지만, 상수는 값을 변경할 수 없으므로 불가능하다.
대부분의 연산자는 피연산자의 값을 읽어서 연산에 사용할 뿐, 피연산자의 타입이나 값을 변경시키지 않는다. 오직 대입연산자와 증감연산자만 피연산자의 값을 변경한다.
일반적으로 단항 연산자는 피연산자의 왼쪽에 위치하지만, 증가 연산자 ‘++’와 감소 연산자 ‘–‘는 양쪽 모두 가능하다. 피연산자의 왼쪽에 위치하면 전위형(prefix), 오른쪽에 위치하면 후위형(postfix)이라고 한다.
전위형과 후위형 모두 피연산자의 값을 1 증가 또는 감소시키지만, 증감연산자가 수식이나 메서드 호출에 포함된 경우 전위형과 후위형의 결과가 다르다. 그러나 독립적인 하나의 문장으로 쓰인 경우에는 차이가 없다.
전위형 | 값이 참조되기 전에 증가시킨다. | j = ++i; |
후위형 | 값이 참조된 후에 증가시킨다. | j = i++; |
식을 계산하기 위해서는 식에 포함된 변수의 값을 읽어 와야 하는데, 전위형은 변수(피연산자)의 값을 먼저 증가시킨 후에 변수의 값을 읽어오는 반면, 후위형은 변수의 값을 먼저 읽어온 후에 값을 증가시킨다.
증감연사자를 사용하면 코드가 간결해지지만, 지나치면 복잡해서 이해하기 어려워진다. 따라서 하나의 식에서 증감연산자의 사용을 최소화하고, 식에 두 번 이상 포함된 변수에 증감연산자를 사용하는 것은 피해야 한다.
감소연산자 –는 1 감소시킨다는 것만 빼고 증가 연산자와 동일하다.
2.2 부호 연산자 + -
부호 연산자 ‘-‘는 피연산자의 부호를 반대로 변경한 결과를 반환한다. 피연산자가 음수면 양수, 양수면 음수가 연산의 결과가 된다. 부호연산자 ‘+’는 쓰이는 경우가 거의 없다. ‘-‘가 있어서 형식적으로 추가한 것이다.
부호 연산자는 boolean형과 char형을 제외한 기본형에만 사용할 수 있다.
산술 연산자
3.1 사칙 연산자 + - * /
사칙 연산자는 가장 많이 쓰이는 연산자들이다. 곱셈(*), 나눗셈(/), 나머지(%) 연산자가 덧셈(+), 뺄셈(-) 연산자보다 우선순위가 높다.
피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없다. 만일 0으로 나눈다면 실행 시 에러(ArithmeticException)가 발생할 것이다.
부동 소수점값인 0.0f, 0.0d로 나누는 것은 가능하지만 그 결과는 Infinity(무한대)이다.
class Operator {
public static void main(String[] args) {
byte a = 10;
byte b = 20;
byte c = a + b;
System.out.println(c);
}
}
위 예제를 컴파일하면 에러가 발생한다. a와 b는 모두 int
형보다 작은 byte
형이기 때문에 연산자 ‘+’는 두 피연산자들의 자료형을 int
형으로 변환한 다음 연산을 수행한다. 따라서 연산결과인 int
형 값을 형변환없이 byte
의 변수에 저장하려고 했기 때문에 에러가 발생하는 것이다.
실제로 형변환을 하여 출력해보면 44가 출력된다. 10 * 30은 300이지만, 큰 자료형에서 작은 자료형으로 변환하면 데이터의 손실이 발생하므로 값이 바뀔 수 있다.
class Operator {
public static void main(String[] args) {
int a = 1_000_000;
int b = 2_000_000;
long c = a * b;
System.out.println(c);
}
}
변수 c의 자료형이 long
이어서 결과 값인 ‘2,000,000,000,000’
이 출력될 것 같지만, 결과는 다른 값이 출력된다. 그 이유는 int
타입과 int
타입의 연산결과는 int
타입인데 a * b
의 결과값이 이미 int
값으로 결정이 되었기 때문에 long
형으로 자동 형변환되어도 값이 변하지 않는다. 올바른 값을 원한다면 변수 a나 b를 long
타입으로 형변환해야 한다.
사칙연산의 피연산자로 문자도 가능하다. 문자는 해당 문자의 유니코드(부호없는 정수)로 바뀌어 저장되므로 문자간의 사칙연산은 정수간의 연산과 동일하다.
문자 ‘2’를 숫자로 변환하려면 문자 ‘0’을 빼주면 된다. 문자 ‘2’의 유니코드는 50이고, 문자 ‘0’은 48이므로, 두 문자간의 뺄셈은 2를 결과로 얻는다. 유니코드를 보면 문자의 유니코드가 연속적으로 배치가 되어 있다.
이를 이용하여 대소문자 변환 프로그램을 작성할 수 있다.
class Operator {
public static void main(String[] args) {
char lowerCase = 'a';
char upperCase = (char)(lowerCase - 32);
System.out.println(upperCase);
}
}
대문자 A
가 소문자 a
보다 32 작으므로 소문자 a
의 코드값에서 32를 빼면 대문자 A
가 된다. 반대로 대문자에 32를 더하면 소문자가 된다.
| 참고 | char형과 int형 간의 뺄셈연산 결과는 int형이므로, 연산 후 형변환을 해주어야 한다.
3.2 나머지 연산자 %
나머지 연산자는 왼쪽의 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 결과로 반환하는 연산자이다. 나머지 연산자 는 나눗셈과 마찬가지로 오른쪽 피연산자로 0을 사용할 수 없다. 주로 짝수, 홀수, 또는 배수 검사 등에 주로 사용된다.
나머지 연산자는 나누는 수로 음수도 허용한다. 그러나 부호는 무시되고 결과는 음수의 절대값으로 나눈 나머지 값과 같다. 피연산자의 부호를 모두 무시하고, 나머지 연산을 한 결과에 왼쪽 피연산자의 부호를 붙이면 된다.
Comments
JAVA 의 다른 글
-
서블릿 컨테이너(Servlet Container)란? 05 May 2021
-
지네릭스, 열거형, 애너테이션 27 Oct 2020
-
컬렉션 프레임웍 2편 16 Oct 2020
-
컬렉션 프레임웍 1편 14 Oct 2020
-
날짜와 시간 & 형식화 12 Oct 2020
-
java.lang패키지와 유용한 클래스 29 Sep 2020
-
예외처리 24 Sep 2020
-
객체지향 프로그래밍 II 2편 21 Sep 2020
-
객체지향 프로그래밍 II 1편 19 Sep 2020
-
객체지향 프로그래밍 I 2편 18 Sep 2020
-
객체지향 프로그래밍 I 1편 16 Sep 2020
-
배열 array 14 Sep 2020
-
조건문과 반복문 if, switch, for, while statement 13 Sep 2020
-
연산자 Operator 2편 13 Sep 2020
-
연산자 Operator 1편 11 Sep 2020
-
변수 Variable 2편 09 Sep 2020
-
변수 Variable 1편 08 Sep 2020
-
자바를 시작하기 전에 07 Sep 2020
-
래퍼 클래스(Wrapper Class)란 무엇인가 30 Aug 2020
-
java.lang.Math 29 Aug 2020
-
진수 변환, 형 변환 29 Aug 2020
-
Arrays.sort() 29 Aug 2020
-
Enhanced for loop 20 Aug 2020
-
toCharArray() 20 Aug 2020