단항 연산자
증감 연산자 (++, --)
피연산자에 저장된 값을 1 증가 또는 감소시킨다.
정수와 실수는 가능하지만, 상수는 불가능하다.
타입 | 설명 | 사용 예시 |
---|---|---|
전위형 (prefix) | 값이 참조되기 전에 증감시킨다. | j = ++i; |
후위형 (postfix) | 값이 참조된 후에 증감시킨다. | j = i++; |
부호 연산자 (+, -)
부호 연산자 '-'는 피연산자의 부호를 반대로 변경한 결과를 반환한다.
boolean형과 char형을 제외한 기본형에만 사용 할 수 있다.
산술 연산자
산술 연산자에는 사칙연산자(+, -, *, /)와 나머지 연산자(%)가 있다.
사칙연산자 (+, _, *, /)
덧셈과 뺄셈보다 곱셈과 나눗셈의 우선순위가 높다.
나누기 연산
피연산자가 정수형인 경우, 나누는 수로 0을 사용 할 수 없다.
나누기 연산자의 피연산자가 모두 int 타입인 경우, 연산결과 역시 int 타입이 되며, 소수점 이하는 반올림 되지 않고 버려진다.
피연산자 중 어느 한쪽을 실수형으로 형변환 하게 되면 나머지 한 쪽도 실수형으로 자동 형변환이 되어 실수형의 값을 결과로 얻을 수 있다.
피연산자가 정수인 경우, 나누는 수로 0을 사용 할 수 없다. 하지만, 피연산자 중 한쪽이라도 실수형으로 바꾸게 되면, 결과는 Infinity가 된다.
자동 형변환
int형보다 작은 크기의 type으로 + 연산을 수행하게 되면 자료형을 자동으로 int로 변환 후 연산을 수행한다.
따라서 byte형 + byte형 연산의 수행 결과는 int형이 된다. byte 타입의 변수에 byte형 + byte형 의 연산결과를 저장하려 한다면, 에러가 발생한다.
또한, byte형 + byte형 연산의 수행 결과가 byte형의 표현 범위를 넘어서는 경우, 데이터 손실이 발생하게 된다.
마찬가지로 int형 * int형 연산 수행 결과는 int형이므로 int형의 표현 범위를 넘어서는 경우 long으로 형변환이 되었다 하더라도 데이터 손실이 발생한다.
문자형(char)의 연산
문자(char)형 변수는 부호없는 정수인 유니코드로 저장되므로, 연산이 가능하다.
char c2 = c1 + 1; // '+'연산의 결과는 int형이므로 char형 변수에 담을 수 없다.
char c2 = 'a' + 1; // 변수가 아닌 리터럴 간의 연산은 컴파일시 컴파일러가 미리 계산하여 오류가 없다.
리터럴 간 연산은 컴파일시 컴파일러가 미리 알 수 있는 값이기 때문에 컴파일 후 변환되게 된다.
ex. 60 * 60 → 360, 'a' + 1 → 'b'
하지만 변수가 포함된 연산은 컴파일시 계산 할 수 없으므로 런타임에 형변환이 발생하여 오류가 발생하게 된다.
런타임에 연산이 되지 않음으로 360을 60 * 60과 같이 표기하였다 하여 런타임 성능에 영향을 주지도 않는다.
나머지 연산자 (%)
왼쪽 피연산자를 오른쪽 피연산자로 나누고 난 나머지.
오른쪽 피연산자로 0을 사용 할 수 없다.
나누는 수로 음수도 허용하지만, 부호는 무시된다. 결과는 음수의 절대값으로 나눈 나머지와 결과가 같다.
실행결과는 왼쪽 피연산자의 부호를 따른다.
비교 연산자
두 피연산자를 비교하는 데 사용된다. 연산결과는 오직 true와 false 둘 중 하나.
비교하는 피연산자의 타입이 서로 다른 경우, 자동 형변환이 발생한다.
대소비교 연산자 (<, >, <=, >=)
두 피연산자의 값의 크기를 비교하는 연산자.
기본형 변수 중에서는 boolean을 제외한 모든 자료형에 사용 할 수 있다.
참조형 변수에는 사용 할 수 없다.
등가비교 연산자 (==, !=)
두 피연산자가 같은지, 다른지 비교하는 연산자.
모든 변수형에 사용 할 수 있다. 기본형의 경우 변수에 저장된 값을 비교 할 수 있고, 참조형의 경우 객체의 주소값을 비교한다.
서로 다른 기본형에 사용될 경우, 형변환이 수행된다.
ex.
10.0 == 10.0f true
0.1==0.1f false // 0.1f는 0.10000000149011612, 0.1은 0.10000000000000001으로 저장된다.
double과 float타입을 비교하기 위해서는 double 타입을 float으로 형변환 한 후 비교해야 한다.
문자열의 비교
문자열은 equals() 메소드로 비교한다. '==' 연산자로 비교할때는 같은 객체인지 비교하게 된다.
String str1 = "abc";
String str2 = new String("abc");
String str3 = "abc";
System.out.printf("str1 == str2 ? %b%n", str1 == str2); // false
System.out.printf("str1 == str3 ? %b%n", str1 == str3); // true
System.out.printf("str1.equals(\"abc\") ? %b%n", str1.equals("abc")); // true
System.out.printf("str2.equals(\"abc\") ? %b%n", str2.equals("abc")); // true
System.out.printf("str2.equals(\"ABC\") ? %b%n", str2.equals("ABC")); // false
System.out.printf("str2.equalsIgnoreCase(\"ABC\") ? %b%n", str2.equalsIgnoreCase("abc")); // true
대소문자를 구분하고 싶지 않다면 equalsIgnoreCase() 메서드를 사용한다.
논리 연산자
둘 이상의 조건을 그리고(AND)나 또는(OR)로 연결하여 하나의 식으로 표현 할 때 사용한다.
논리 연산자 (&&, ||, !)
'&&': 그리고(AND)
'||': 또는(OR)
1) x는 10보다 크고 20보다 작다.
x > 10 && x < 20
2) i는 2의 배수 또는 3의 배수다.
i % 2 == 0 || i % 3 == 0
3) i는 2의 배수 또는 3의 배수지만 6의 배수는 아니다.
(i % 2 == 0 || i % 3 == 0) && (i % 6 != 0) // '&&'연산은 '||' 연산보다 우선순위가 높다.
4) 문자 ch는 숫자 '0'~'9'이다.
'0' <= ch && ch <= '9' // 유니코드에서 문자 '0'(48)~'9'(57)가 연속적이므로 가능하다.
5) 문자 ch는 대문자 알파벳 또는 소문자 알파벳이다.
('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') // 유니코드에서 알파벳이 연속적으로 배열되므로 가능하다.
효율적인 연산
연산 OR(||)의 경우, 피연산자 중 어느 한쪽만 true여도 연산결과가 true가 되므로 좌측 피연산자가 true인 경우 우측 피연산자의 값은 평가하지 않는다.
AND(&&)연산도 마찬가지고 좌측 피연산자가 false인 경우 우측 피연산자의 값을 평가하지 않는다.
그래서 같은 조건식이라도 피연산자의 위치에 따라서 연산속도가 달라질 수 있다.
논리 부정 연산자 (!)
피연산자가 true이면 false를, false이면 true를 반환한다.
// ch는 소문자가 아니다.
(ch < 'a' || ch > 'z')
!('a' <= ch && ch <= 'z') // 이해하기 쉽다.
비트 연산자
비트 연산자 (& | ^ ~ << >>)
비트단위의 논리 연산. 피연산자를 이진수로 표현했을 때의 연산. 피연산자로 실수는 허용하지 않는다. 정수(문자 포함)만 허용.
|(OR) 피연산자 중 한쪽의 값이 1이면, 1을 결과로 얻는다. 그 외에는 0을 얻는다.
&(AND) 피연산자 양 쪽이 모두 1이어야만 1을 결과로 얻는다. 그 외에는 0을 얻는다.
^(XOR) 피연산자의 값이 서로 다를때만 1을 결과로 얻는다. 같을 때는 0을 얻는다.
'|'연산자는 특정 비트의 값을 변경할 때, '&'연산자는 특정 비트의 값을 뽑아낼 때 사용한다.
'^'연산자는 간단한 암호화에 사용된다.
비트 연산에도 피연산자의 타입을 일치시키는 '산술 변환'이 일어날 수 있다.
비트 전환 연산자 (~)
피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꾼다.
피연산자의 '1의 보수'를 얻을 수 있다. 1의 보수에 1을 더하면 음수가 된다.
비트 전환 연산자의 피연산자의 타입이 int보다 작으면 int로 자동 형변환이 된 값을 얻는다.
쉬프트 연산자 (<< >>)
피연산자를 2진수로 표현했을 때 각 자리를 오른쪽 또는 왼쪽으로 이동한다.
저장범위를 벗어난 값들은 버려지고, 빈자리는 0으로 채워진다.
'>>'연산자는 부호있는 정수는 부호를 유지하기 위해 왼쪽 피연산자가 음수인경우 빈자리를 1로 채운다.
쉬프트 연산자의 좌측 피연산자는 산술변환이 적용되어 int보다 작은 타입은 int타입으로 자동 변환되고 연산결과 역시 int타입이 된다. 우측 피연산자의 경우 산술변환이 적용되지 않는다.
2진수 n자리를 왼쪽으로 이동하면 피연산자에 2ⁿ을 곱한 결과를, 오른쪽으로 이동하면 2ⁿ을 나눈 결과를 얻는다. 2진수이기 때문.
'x << n' 또는 'x >> n'에서 n의 값이 자료형의 bit수 보다 크면, 자료형의 bit수로 나눈 나머지만큼만 이동한다.
ex) '8 >> 32': 아무일도 하지 않음. '8>>34' == '8>>2'
n은 정수만 가능하며, 음수인경우 부호없는 정수로 변환된다.
2의 배수로 곱하거나 나누는 연산에서 '*', '/' 연산보다 속도가 빠르지만 가독성이 떨어지기 때문에 속도에 민감할 경우에 사용된다.
그 외 연산자
조건 연산자 (? :)
조건연산자는 조건식, 식1, 식2를 필요로 하는 삼항연산자이며 삼항 연산자는 하나뿐이다.
result = (조건식 ? 식1 : 식2)
if(조건식){
result = 식1
} else{
result = 식2
}
조건식이 true일 때, 연산 결과는 식1이 되며 조건식이 false일 때, 연산 결과는 식2가 된다.
조건 연산자의 식1과 식2의 피연산자의 타입이 다른 경우, 산술변환이 발생한다.
대입연산자
대입연산자 (=)
변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장한다.
가장 낮은 우선순위를 갖고 있다.
연산 진행방향이 오른쪽에서 왼쪽이다.
리터럴이나 상수같이 값을 저장 할 수없으면 왼쪽 피연산자가 될 수 없다.
복합 대입연산자 (op=)
i += 3;
i = i +3;
i *= 10 + j;
i = i * (10 + j);