연산자는 크게 6가지 토픽으로 나눌 수 있는데요.
[ 1.연산자 > 2.단항 연산자 > 3. 산술 연산자 > 4. 비교연산자 > 5.논리 연산자 > 6.그 외의 연산자]
제일 먼저 1.연산자 안에 세부 내용들을 살펴보겠습니다.
1.1 연산자와 피연산자
연산자는 말그대로 '연산을 수행하는 기호'를 말하는데요.
예를 들어 '+'기호는 덧셈 연산을 수행하는 '덧셈 연산자'가 되는 것입니다.
이때, 연산자가 연산을 수행하려면 반드시 연산의 대상이 있어야 하는데요.
이것을 '피연산자'라고 합니다.
피연산자로는 상수,변수 또는 식 등을 사용할 수 있습니다.
x + 3
이와 같이 식이 있을 때, '+'는 덧셈 연산자이고, 변수 x와 상수 3은 이 연산자의 피연산자가 되는 것이다.
위의 식을 봐서 알겠지만 대부분의 연산자는 이처럼 두 개의 피연산자를 필요로 하며, 하나 또는 세 개의 피연산자를
필요로 하는 연산자도 있다.
*연산자는 피연산자로 연산을 수행하고 나면 항상 결과값을 반환한다.*
1.2 식과 대입연산자
위의 1.1 내용을 바탕으로 식이 무엇인지 표현을 해보자면
연산자와 피연산자를 조합하여 계산하고자하는 바를 표현한 것을 '식' 이라고 한다.
그리고 식을 계산하여 결과를 얻는 것을 '식을 평가'한다고 한다.
하나의 식을 평가(계산)하면, 단 하나의 결과를 얻는데,
만일 x의 값이 5라면, 아래의 식을 평가한 결과는 23이 된다.
4 * x +3
작성한 식을 프로그램에 포함시키려면, 식의 끝에 ';'를 붙여서 문장으로 만들어야 한다.
4 * x +3; // 문장
예를 들어 변수 x의 값이 5일 때, 위의 문장은 식이 평가되어
23이라는 결과를 얻지만 이 값이 어디에도 쓰이지 않고 사라지기 때문에 이 문장은 아무런 의미가 없다.
그래서 대입연산자'='를 사용해서 변수와 같이 값을 저장할 수 있는 공간에 결과를 저장해야한다.
y = 4 * x + 3;
> y = 4 * 5 + 3;
> y + 23; //식의 평가결과가 변수 y에 저장된다.
그 다음에는 변수 y에 저장된 값을 다른 곳에 사용하거나 화면에 출력함으로써 의미있는 결과를 얻을 수 있다.
y = 4 * x + 3;
System.out.println(y); // 변수 y의 값을 화면에 출력
만약 식의 평가결과를 출력하기만을 원할 뿐, 이 값을 다른 곳에 사용하지 않을 것이라면
다음과 같이 변수에 저장하지 않고 println메서드의 괄호()안에 직접 식을 써도 된다.
System.out.println(4 * x + 3);
> System.out.println(23); // 23이 화면에 출력된다.
1.3 연산자의 종류
연산자는 크게 산술, 비교, 논리, 대입 이렇게 4가지로 나눌 수 있다.
산술, 비교, 대임 연산자는 이미 알고 있는 것들이고, 논리 연산자도 쉽게 이해가 될것이다.
-피연산자의 개수에 의한 분류
피연산자의 개수가 하나면 '단항 연산자', 두 개면 '이항 연산자', 세 개면 '삼항 연산자'라고 부른다.
대부분의 연산자는 '이항 연산자' 이고, 삼항 연산자는 오직'? :' 하나뿐이다.
- 3 - 5
빨간색 기호와 파란색 기호가 둘 다 같은 '-'기호로 나타내지만 엄연히 다른 연산자이다.
빨간색은 '부호 연산자' 이고, 파란색은 '뺄셈 연산자'이다.
이처럼 서로 다른 연산자의 기호가 같은 경우도 있는데, 이럴 때는 피연산자의 개수로 구분이 가능하다.
위와 같이 연산자를 기능별, 피연산자의 개수별로 나누어 분류하는 것은 곧이어 배우게 될 '연산자의 우선순위' 때문이기도 하다.
1.4 연산자의 우선순위와 결합규칙
연산자의 우선순위는 대부분 우리가 학교 정규과정에 배운 수학적 상식을 그대로 따라가면 된다.
연산자의 결합규칙
우선순위가 같다고 해서 아무거나 먼저 처리하는 것은 아니고 나름대로의 규칙을 가지고 있는데
그 규칙을 한번 살펴보자.
대부분 왼쪽에서 오른쪽의 순서로 연산을 수행하고, 단항 연산자와 대입 연산자만 그 반대로,
오른쪽에서 왼쪽의 순서로, 연산을 수행한다.
(a) 연산자의 결합규칙이 왼쪽에서 오른쪽인 경우
3 + 4 - 5
→
(b)연산자의 결합규칙이 오른쪽에서 왼쪽인 경우
x = y =3
←
+ (b)에서 대입연산자는 연산자의 결합규칙이 R에서 L이므로 수식에서
오른쪽의 대입연산자부터 처리한다. 따라서 'y + 3'이 먼저 수행되어서
y에 3이 저장되고 그 다음에 'x = 3'이 수행되어 x에도 3이 저장된다.
∝참고 - 'x = y =3;' 은 'y = 3' 과 'x = 3;' 을 하나의 문장으로 합쳐놓은 것으로 이해해도 좋다.
앞서 배운 연산자의 우선순위에 대해서 정리하면 다음과 같다.
1. 산술 > 비교 > 논리 > 대입. 대입은 제일 마지막에 수행된다.
2. 단항(1) > 이항(2) > 삼항(3). 단항 연산자의 우선순위가 이항 연산자보다 높다.
3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.
♣주의 : 단항연산자에 있는 '+' 와 '-' 는 부호연산자이고, '(type)'은 형변환 연산자이다.
1.5 산술변환
이항 연산자는 두 피연산자의 타입이 일치해야 연산이 가능하므로, 피연산자의 타입이 서로 다르다면
연산 전에 형변환 연산자로 타입을 일치시켜야 한다.
예를 들어 int타입과 float타입을 덧셈하는 경우, 형변환 연산자를 사용해서 피연산자의 타입을 둘 다 int 또는
float 로 일치시켜야 한다.
int i = 10;
float f = 20.0f;
float result = f + (float)i; // 형변환으로 두 피연산자의 타입을 일치
대부분의 경우, 두 피연산자의 타입 중에서 더 큰 타입으로 일치시키는데, 그 이유는 작은 타입으로 형변환하면
원래의 값이 손실될 가능성(오버플로우)이 있기 때문이다.
작은 타입에서 큰 타입으로 형변환하는 경우, 자동적으로 형변환되므로 형변환 연산자를 생략할 수 있다.
float result = f + i; // 큰 타입으로 형변환 시, 형변환연산자 생략가능
이처럼 연산 전에 피연산자 타입의 일치를 위해 자동 형변환되는 것을 '산술 변환' 또는 '일반 산술 변환'
이라 하며, 이 변환은 이항 연산에서뿐만 아니라 단항 연산에서도 일어난다.
'산술 변환'의 규칙은 다음과 같다.
(a) 두 피연산자의 타입을 같게 일치시킨다.(보다 큰 타입으로 일치)
long + int > long + long > long
float + int > float + float > float
double + float > double + double > double
(b) 피연산자의 타입이 int 보다 작은 타입이면 int로 변환된다.
byte + short > int + int > int
char +short > int + int > int
∝참고 - 모든 연산에서 '산술변환이' 일어나지만, 쉬프트 연산자(<<,>>), 증감 연산자(++,--)는 예외이다.
여기서 한 가지 주목해야할 점은 연산결과의 타입이다.
연산결과의 타입은 피연산자의 타입과 일치한다. 이게 무슨 말이냐면
예를 들어 intd와 int의 나눗셈 연산결과는 int일 것이다.
intg는 float와 double과 같은 실수형이 아니기 때문에 소수점 이하는 버려진다.
그래서 아래의 식 '5나누기 2'의 결과가 2.5가 아닌 2이다.
int / int > int
5 / 2 > 2
그렇다면 2.5라는 결과값을 얻으려면 어떻게 해야할까?
그렇다. 피연산자 중 어느 한 쪽을 float와 같은 실수형으로 형변환해야 한다.
그러면, 다른 한 쪽은 산술 변환의 첫 번째 규칙에 의해 자동적으로 형변환되어 두 피연산자 모두
실수형이 되고, 연산결과 역시 실수형의 값을 얻을 수 있다.
int / (float)int > int / float > float / float >float
5 / (float)2 > 5 / 2.0f > 5.0f / 2.0f > 2.5f
결국 산술 변환이란, 용어가 좀 거창하지만, 연산 직전에 발생하는 자동 형변환일 뿐이다.
아래의 두 가지 규칙만 잘 기억해두자.
1- 두 피연산자의 타입을 같게 일치시킨다(보다 큰 타입으로 일치)
2- 피연산자의 타입이 int보다 작은 타입이면 int로 변환한다.
2. 단항 연산자
2.1 증감 연산자 ( ++ -- )
증감연산자의 피연산자로 정수와 실수가 모두 가능하지만, 상수는 값을 변결할 수 없으므로 가능하지 않다.
앞서 형변환에서 설명한 것과 같이 대부분의 연산자는 피연산자의 값을 읽어서 연산에 사용할 뿐, 피연산자의
타입니다. 값을 변경시키지 않는다. (=캐스팅(형변환)이 필요없어짐)
오직 대입연산자와 증감연산자만 피연산자의 값을 변경한다.
∝참고- 증감연산자는 일반 산술 변환에 의한 자동 형변환이 발생하지 않으며, 연산결과의 타입은 피연산자의 타입과 같다.
- 증가 연산자(++) : 피연산자의 값을 1 증가시킨다.
- 감소 연산자(- - ) : 피연산자의 값을 1 감소시킨다.
+ 일반적으로 단항 연산자는 피연산자의 왼쪽에 위치하지만,
증가 연산자와 감소 연산자는 양쪽 모두 가능하다.
피연산자의 왼쪽에 위치하면 '전위형',
오른쪽에 위치하면 '후위형'
이라고 한다.
전위형과 후위형 모두 피연산자의 값을 1 증가 또는 감소시키지만, 증감연산자가
수식이나 메서드 호출에 포함된 경우 전위형일 때와 후위형일 때의 결과가 다르다.
=====>전위형 / 값이 참조되기 전에 증가시킨다. / ex) j = ++i;
=====>후위형 / 값이 참조된 후에 증가시킨다. / ex) j = i++;
그러나 '++i;'와 'i++;'처럼 증감연산자가 수식이나 메서드 호출에 포함되지 않고 독립적인
하나의 문장으로 쓰인 경우 둘 다 차이가 없다.
++i; // i 의 값을 1 증가시킨다.
i++; // 위의 문장과 차이가 없다.
이 경우에는 어떤 수식에 포함된 것이 아니라 단독적으로 사용된 것이기 때문에, 증감연산자(++)를
피연산자의 왼쪽,오른쪽에 사용한 경우의 차이가 없다.
그러나 다른 수식에 포함되거나 메서드의 매개변수로 사용된 경우,
즉 단독으로 사용하지 않은 경우 전위형과 후위형의 결과는 다르다.
public class OperatorEx2 {
public static void main(String[] args) {
int i = 5, j = 0;
j = i++;
System.out.println("j=i++; 실행 후, i+" + i +", j="+ j);
i=5;
j=0;
j = ++i;
System.out.println("j=++i; 실행 후, i+" + i +", j="+ j);
}
}
result) j=i++; 실행 후, i=6, j=6
result) j=i++; 실행 후, i=6, j=5
전위형은 변수(피연산자)의 값을 먼저 증가시킨 후에 변수의 값을 읽어오는 반면, 후위형은 변수의 값을 먼저 읽어온 후에 값을 증가시킨다.
다음은 메서드 호출에 증감연산자가 사용된 예이다.
public class OperatorEx3 {
public static void main(String[] args) {
int i = 5, j = 5;
System.out.println(i++);
System.out.println(++j);
System.out.println("i = " + i + ", j = " +j);
}
}
result)
5
6
i = 6, j = 6
풀이 : i는 값이 증가되기 전에 참조되므로 println()에게 i에 저장된 값 5를 넘겨주고 나서 i 의 값이
증가하기 때문에 5가 출력되고, j 의 경우 j에 저장된 값을 증가 시킨 후에 값을 넘겨주므로 6이 출력된다.
결과적으로는 모두 1씩 증가되어 6이 된다.
주의사항 : 증감연산자를 사용하면 코드가 간결해지지만, 하나의 식에서 증감연산자의 사용을 최소화하고, 식에
두 번 이상 포함된 변수에 증감연산자를 사용하는 것은 피해야 한다.
2.2 부호 연산자 + -
부호 연산자는 boolean형과 char형을 제외한 기본형에만 사용할 수 있다.
3. 산술 연산자
산술 연산자에는 사칙 연산자(+,-,*,/)와 나머지 연산자(%)가 있다.
3.1 사칙 연산자 + - * /
피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없다. 만일 0으로 나눈다면, 실행 시에 에러가 발생할 것이다.
한 가지 눈여겨볼 것은 10을 4로 나눈 결과가 2.5가 아닌 2라는 것이다.
int int int
10 / 4 > 2 // 소수점 이하는 버려진다.
나누기 연산자의 두 피연산자가 모두 int타입인 경우, 연산결과 역시 int 타입이다.
int타입은 소수점을 저장하지 못하므로 정수만 남고 소수점 이하는 버려진다.
이 때, 반올림이 발생하지 않는다는 것에 주의하자.
그래서 올바른 연산결과를 얻기 위해서는 두 피연산자 중 어느 한 쪽을 실수형으로 형변환해야 한다.
그래야만 다른 한쪽도 같이 실수형으로 자동 형변환되어 결국 실수형의 값을 결과로 얻는다.
int float float float float
10 / 4.0f > 10.0f / 4.0f > 2.5f
위의 연산과정을 보면, 두 피연산자의 타입이 일치하지 않으므로 int타입보다 범위가 넓은
float타입으로 일치시킨 후에 연산을 수행하는 것을 알 수 있다.
이제 float타입과 float타입의 연산이므로 연산결과 역시 float타입이다.
+ int형에서 더 작은 byte형으로 바꾸면 데이터 손실이 발생한다.
결국 byte형에서 표현할 수 있는 값까지만 표현된다.
사칙연산의 피연산자로 숫자뿐만 아니라 문자도 가능하다.
문자는 실제로 해당 문자의 유니코드(부호없는 정수)로 바뀌어 저장되므로 문자간의 사칙연산은
정수간의 연산과 동일하다.
ex) 'd' - 'a' > 100 - 97 > 3
+ 상수 또는 리터럴 간의 연산은 실행 과정동안 변하는 값이 아니기 때문에, 컴파일 시에
컴파일러가 계산해서 그 결과로 대체 함으로써 코드를 보다 효율적으로 만든다.
+println메서드는 값을 출력하고 줄을 바꾸지만, print메서드는 줄을 바꾸지 않고 출력한다. 매개변수없이 println메서드를 호출하면, 아무 것도 출력하지 않고 단순히 줄을 바꾸고 다음 줄의 처음으로 출력위치를 이동시킨다.
+1000f 는 1000.0f와 같다.
+Math.round() 를 시용하면 좀 더 간단히 반올림 할 수 있다.
3.2 나머지 연산자 %
public class OperatorEx20 {
public static void main(String[] args) {
System.out.println(-10%8) ;
System.out.println(10%-8) ;
System.out.println(-10%-8) ;
}
}
result) -2
2
-2
나머지 연산자(%)는 나누는 수로 음수도 허용한다. 그러나 부호는 무시되므로 결과는 음수의
절대값으로 나눈 나머지와 결과가 같다.
System.out.println(10%8); // 10을 8로 나눈 나머지 2가 출력된다.
System.out.println(10%-8); // 위와 같은 결과를 얻는다.
그냥 피연산자의 부호를 모두 무시하고, 나머지 연산을 한 결과에 왼쪽 피연산자(나눠지는 수)의 부호를 붙이면 된다.
'JAVA' 카테고리의 다른 글
선택정렬, 삽입정렬구현 (0) | 2022.01.17 |
---|---|
Chapter 05 배열 (Array) - 220103~ (0) | 2022.01.13 |
Java 수업복습(220110~) - 조건문과 반복문(if, switch, for, while statement) (0) | 2022.01.11 |
java 수업복습(220106) - 연산자(Operator) (0) | 2022.01.10 |
Java 형변환(Casting)이란 (0) | 2022.01.07 |