연산자와 피연산자
연산자는 '연산을 수행하는 기호'를 의미한다. 연산자가 연산을 수행하기 위해선 반드시 연산의 대상이 있어야 하는데, 이것을 피연산자(operand)라고 한다. 피연산자에는 상수, 변수, 식 등이 있다.
- 연산자(operator): 연산을 수행하는 기호(+, -, *, / 등)
- 피연산자(operand) 연산자의 작업 대상(변수, 상수, 리터럴, 수식)
대부분의 연산자는 두 개의 피연산자를 필요로 하지만, 하나 또는 세 개의 피연산자를 필요로 하는 연산자도 있다. 연산자는 피연산자로 연산을 수행하고 나면 항상 결과값을 반환한다.
식과 대입연산자
식(expression)
연산자와 피연산자를 조합하여 계산하고자 하는 바를 표현한 것을 '식(expression)'이라고 하고, 이러한 식을 계산하여 결과를 얻는 것을 '식을 평가(evaluation)한다'고 한다. 이때, 하나의 식을 평가(계산)하면, 단 하나의 결과를 얻는다. 만약 x의 값이 5라면, 아래의 식을 평가한 결과는 23이 된다.
4 * x + 3
이렇게 작성한 식을 자바 프로그램 내 포함시키려면 식의 끝에 세미콜론(;)을 붙여서 문장(statement)로 만들어야 한다.
4 * x + 3; // 문장(statement)
-> 4 * 5 + 3;
-> 23;
대입연산자
이와 같이 식이 평가되어 결과(23)를 얻더라도, 이 값은 어디에도 쓰이지 않기 때문에 위의 문장은 아무런 의미가 없다. 그래서 대입 연산자(=)를 이용해 변수와 같이 값을 저장할 수 있는 공간에 결과를 저장해야 한다.
y = 4 * x + 3;
-> y = 4 * 5 + 3;
-> y = 23;
연산자의 기능별 분류
종류 | 연산자 | 설명 |
산술 연산자 | + - * / % << >> | 사칙연산(+, -, *, /)과 나머지 연산 |
비교 연산자 | > < >= <= == != | 크고 작음과 같고 다름을 비교 |
논리 연산자 | && || ! & | ^ ~ | '그리고(AND)'와 '또는(OR)'으로 조건을 연결 |
대입 연산자 | = | 우변의 값을 좌변에 저장 |
기타 | (type) ? : instanceof | 형변환 연산자, 삼항 연산자, instanceof연산자 |
연산자는 위의 표와 같이 크게 산술, 비교, 논리, 대입 연산자 4가지로 나눌 수 있다.
산술 연산자
- 일상생활의 수학과 동일하게 곱셈(*), 나눗셈(/), 나머지(%) 연사자가 덧셈(+), 뺄셈(-) 연산자보다 우선순위가 높아 먼저 처리된다.
- 피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없다(0으로 나눈다면 에러가 발생).
예제1
...
int a = 10;
int b = 10;
System.out.println("%d / %d = %d", a, b, a / b); // 10 / 4 = 2
System.out.println("%d / %f = %f", a, (float)b, a / b); // 10 / 4.000000 = 2.500000
나누기 연산자의 두 피연산자가 모두 int타입인 경우, 연산결과 역시 int타입이다. 그래서 실제 연산결과는 2.5일지라도 int타입의 값인 2를 결과로 얻는다. int타입은 소수점을 지정하지 못하므로 정수가 남고 소수점 이하는 버려지기 때문이다. 이 경우, 반올림이 발생하지 않는다.
10(int) / 4(int) -> 2(int) // 소수점 이하는 버려진다.
올바른 연산결과를 얻기 위해서는 다음과 같이 두 피연산자 중 어느 한 쪽을 실수형으로 형봔환해야 한다. 그렇게 되면 다른 한 피연산자도 실수형으로 자동 형변환되어 실수형의 값을 결과로 얻을 수 있다.
10(int) / 4.0f(float) -> 10.0f(float) / 4.0f(float) -> 2.5f(float)
예제 2
...
byte a = 10;
byte b = 10;
byte c = a + b;
System.out.printLn(c); // 에러 발생!
이 예제를 컴파일하면 에러가 발생한다. a와 b는 모두 int형보다 작은 byte형이기 때문에 연산자 '+'는 이 두개의 피연산자들의 자료형을 int형으로 변환한 다음 연산을 수행한다. 그래서 'a+b'의 연산결과는 byte형이 아닌 int형(4 byte)인 것이다. 4byte의 값을 1byte의 변수에 형변환없이 저장하려고 했기 때문에 에러가 발생하는 것이다.
앞서 2주차에서 형변환에 대해 언급한 적이 있다. 크기가 작은 자료형의 변수를 큰 자료형의 변수에 저장할 때는 자동으로 형변환되지만, 반대로 큰 자료형의 값을 작은 자료형의 변수에 저장하기 위해선 명시적으로 형변환 연산자를 사용하여 변환해줘야 한다.
byte c = (byte) (a + b); // 20
이처럼 자바는 파이썬이나 자바스크립트 같은 동적타입 언어와 다르게 사칙연산 시 자료형의 크기를 항상 고려해야 한다.
비트 연산자
비트 연산자는 피연산자를 비트단위로 논리 연산한다. 피연산자를 이진수로 표현했을 때의 각 자리를 아래의 규칙에 따라 연산을 수행하며, 피연산자로 실수는 허용하지 않고 정수(문자 포함)만 허용한다.
- | (OR연산자): 피연산자 중 한 쪽의 값이 1이면, 1을 결과로 얻는다. 그 외에는 0을 얻는다.
- & (AND연산자): 피연산자 양 쪽이 모두 1이어야만 1을 결과로 얻는다. 그 외에는 0을 얻는다.
- ^ (XOR연산자): 피연산자의 값이 서로 다를 때만 1을 결과로 얻는다. 같을 때는 0을 얻는다.
x | y | x | y | x & y | x ^ y |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
0 | 1 | 1 | 0 | 1 |
0 | 0 | 0 | 0 | 0 |
비트 전환 연산자 ~
이 연산자는 피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꾼다. 논리부정 연산자 '!'와 유사하다.
x | ~x |
1 | 0 |
0 | 1 |
쉬프트 연산자 << >>
이연산자는 피 연산자의 각 자리(2진법으로 표현했을 때)를 오른쪽 또는 왼쪽으로 이동(shift)시킨다. 이때, 자리이동으로 저장범위를 벗어난 값들은 버려지고, 빈자리는 0으로 채워진다.
- 왼쪽(<<)으로 1만큼 이동하는 연산은 2를 곱하는 연산과 동일하다.
- x << n == x * 2^n
- 오른쪽(>>)으로 1만큼 이동하는 연산은 2로 나누는 연산과 동일하다.
- x > n == x / 2^n
비교 연산자
비교 연산자는 두 피연산자를 비교하는 데 사용된다. 주로 조건문과 반복문의 조건식에 사용되며, 연산결과는 오직 true와 false 둘 중의 하나이다. 비교 연산자 역시 이항 연산자이므로 비교하는 피연산자의 타입이 서로 다를 경우에는 자료형의 범위가 큰 쪽으로 자동 형변환하여 피연산자의 타입을 일치시킨 후에 비교한다.
대소비교 연산자 < > <= >=
두 피연산자의 값의 크기를 비교하는 연산자이다. 기본형 중에서는 boolean형을 제외한 나머지 자료형에 다 사용할 수 있지만 참조형에는 사용할 수 없다.
등가비교 연산자 == !=
두 피연산자의 값이 같은지 또는 다른지를 비교하는 연산자이다. 대소비교 연산자와는 달리, 참조형을 포함한 모든 자료형에 사용할 수 있다. 기본형의 경우 변수에 저장되어 있는 값이 같은지를 알 수 있고, 참조형의 경우 객체의 주소값을 저장하기 때문에 두 개의 피연산자(참조변수)가 같은 객체를 가리키고 있는지를 알 수 있다. 기본형과 참조형은 서로 형변환이 가능하지 않기 때문에 등가비교 연산자로 기본형과 참조형을 비교할 수 없다.
문자열의 비교
두 문자열을 비교할 때는, 비교 연산자 '=='대신 equals()라는 메소드를 사용해야 한다. 비교 연산자는 두 문자열이 완전히 같은 것인지 비교할 뿐이므로 문자열의 내용이 같은지 비교하기 위해서는 다음과 같이 equals()를 사용해야 한다.
String str = new String("abc");
// equals()는 두 문자열의 내용이 같으면 true, 다르면 false
boolean resut = str.equals("abc") // 내용이 같으므로 result에 true가 저장된다.
논리 연산자
논리 연산자는 둘 이상의 조건을 '그리고(AND)'나 '또는(OR)'으로 연결하여 하나의 식으로 표현할 수 있게 해준다.
논리 연산자 && || !
- || (OR결합): 피연산자 중 어느 한 쪽만 true이면 true를 결과로 얻는다.
- && (AND결합): 피연산자 양쪽 모두 true여야 true를 결과로 얻는다.
- ! (NOT): 피연산자가 true이면 false를, false면 true를 반환한다.
x | y | x || y | x && y |
true | true | true | true |
true | false | true | false |
false | true | true | false |
false | false | false | false |
효율적인 연산
논리 연산자의 또 다른 특징은 효율적인 연산을 한다는 것이다.
- OR연산의 경우, 두 피연산자 중 어느 한 쪽만 참이어도 전체 연산결과가 참이므로 좌측 피연산자가 true면 우측 피연산자의 값은 평가하지 않는다.
- AND연산의 경우, 두 피연산자 중 어느 한 쪽만 거짓이어도 전체 연산결과가 거짓이므로 좌측 피연산자가 false면 우측 피연산자의 값은 평가하지 않는다.
기타 연산자
조건 연산자 > :
조건 연사자는 조건식, 식1, 식2 모두 세 개의 피연산자를 필요로 하는 삼항 연산자이며, 삼항 연산자는 조건 연산자 하나뿐이다. 아래에서 조건식이 true라면 식1을 반환하고, false라면 식2를 반환한다.
조건식 ? 식 1 : 식2
1. 25 > 24 ? true : false -> true
2. 25 < 24 ? true : false -> false
복합 대입 연산자
대입 연산자는 다른 연산자(op)와 결합하여 'op='와 같은 방식으로 사용될 수 있다.
op= | = |
i += 3; | i = i + 3; |
i -= 3; | i = i - 3; |
i *= 3; | i = i * 3; |
i /= 3; | i = i / 3; |
i %= 3; | i = i % 3; |
i <<= 3; | i = i << 3; |
i >>= 3; | i = i >> 3; |
i &= 3; | i = i & 3; |
i ^= 3; | i = i ^ 3; |
i |= 3; | i = i | 3; |
i *= 10 + j; | i = i * (10 + j); |
instanceof 연산자
참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용한다. 주로 조건문에 사용되며, instanceof의 왼쪽에는 참조변수를, 오른쪽에는 타입(클래스명)이 피연산자로 위치한다. instanceof를 이용한 연산결과로 true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.
// 출처: https://zzdd1558.tistory.com/124
public class InstanceofExam {
public static void main(String[] args) {
A a = new A();
B b = new B();
//객체 a는 자기 자신의 객체이기 때문에 형변환 가능
System.out.println(a instanceof A); // true
//객체 b는 A의 자식객체이기 때문에 A로 형변환 가능
System.out.println(b instanceof A); // true
//객체 a는 B의 부모객체이기때문에 형변환 불가능
System.out.println(a instanceof B); // false
//객체 b는 자기 자신의 객체이기때문에 형변환 가능
System.out.println(b instanceof B); // true
}
}
class A{
...
}
class B extends A{
...
}
연산자 우선순위
식에 사용된 연산자가 둘 이상인 경우, 다음의 표와 같이 연산자의 우선순위에 의해서 연산순서가 결정된다.
참고
자바의 정석(남궁성 저)
'프로그래밍 언어 > Java + Kotlin' 카테고리의 다른 글
[Java] 스터디 6주차: 상속 (0) | 2021.07.07 |
---|---|
[Java] 스터디 5주차: 클래스 (0) | 2021.07.07 |
[Java] 스터디 4주차: 제어문 (0) | 2021.06.24 |
[Java] 스터디 2주차: 자바 데이터 타입, 변수 그리고 배열 (0) | 2021.05.27 |
[Java] 스터디 1주차: JVM은 무엇이며, 자바 프로그램은 어떻게 실행되는가 (0) | 2021.05.20 |