연산을 수행하는 기호
연산자가 연산을 수행하려면 연산의 대상이 있어야한다.
이것이 피연산자, 피연산자는 상수, 변수, 식 등을 사용할 수 있다.
종류 | 연산자 | 설명 |
---|---|---|
산술 연산자 | +, -, *, /, %, <<, >> | 사칙 연산과 나머지 연산 |
비교 연산자 | >, <, >=, <=, ==, != | 크고 작음과 같고 다름을 비교 |
논리 연산자 | &&, ||, !, &, |, ^, ~ | AND와 OR로 조건을 연결 |
대입 연산자 | = | 우변의 값을 좌변에 저장 |
기타 | (type), ?:, instanceof | 형변환 연산자, 삼항 연산자, instanceof 연산자 |
종류 | 결합 규칙 | 연산자 | 우선순위 |
---|---|---|---|
단항 연산자 | <-- | ++, --, +, -, ~, !, (type) | 가장 높음 |
산술 연산자 | --> | *, /, % | |
비교 연산자 | --> | <, >, <=, >=, instanceof | |
논리 연산자 | --> | &| | |
논리 연산자 | --> | ^ | |
논리 연산자 | --> | | | |
논리 연산자 | --> | && | |
논리 연산자 | --> | || | |
삼항 연산자 | --> | ?: | |
대입 연산자 | <-- | =, +=.. 등등 | 가장 낮음 |
1. 산술 > 비교 > 논리 > 대입. 대입은 제일 마지막
2. 단항(1) > 이항(2) > 삼항(3) 항이 많을 수록 우선순위가 낮다
3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행 방향은 -->
byte a = 10;
byte b = 20;
byte c = a + b;
위 코드는 에러가 난다. (int)(a + b)
로 캐스팅 해주라는 에러를 만날 수 있다.
이유는 자바에서 int보다 작은 자료형의 산술연산은 int가 기본 값이다.
char c1 = 'a';
//char c2 = c1 + 1;
char c2 = (char) c1 + 1; // b
char c3 = 'a' + 1; // b
c3++; // c
2행은 에러를 발생시킨다.
2행과 3행의 차이는 무엇일까?
c1 + 1
이라는 연산은 c1이 char형이므로 int형으로 변환한 후 덧셈연산을 수행하게 되고, 이는 int + int = int의 결과를 얻는 것이다.
하지만 그렇다면 4행은 왜 에러를 발생하지 않는 걸까?
이유는 'a' + 1
이 리터럴 간의 연산이기 때문이다.
상수 또는 리터럴 간의 연산은 실행 과정동안 변하는 값이 아니기 때문에, 컴파일 시에 컴파일러가 계산해서 그 결과로 대체함으로써, char 3= 'b'
의 식으로 대체된다.
결과적으로 3행과 4행의 가장 큰 차이는 변수인 c1
과 상수인 'a'
의 차이이다.
//소수 셋째 자리 이하 버리기
float pi = 3.141592f;
float shortPi = (int)(pi * 1000) / 1000f; // 3.141
//흐름
(int)(pi * 1000) / 1000f;
(int)(3141.592f) / 1000f;
3141 / 1000f; // 3141은 inf형이라 곱셈시 소수점이 버려짐
3.141f
//버림이 아닌 반올림 하기
shortPi = (int)(pi * 1000 + 0.5) / 1000f; // 3.142f
//흐름
(int)(pi * 1000 + 0.5) / 1000f;
(int)(3141.592f + 0.5) / 1000f;
(int)(3142.092f) / 1000f;
3142 / 1000f;
3.142
Math.round(pi * 1000)
으로 대체 가능
10 == 10.f
를 비교 할 때 결과는 true를 받게 된 다.
비교연산자 또한 양 쪽의 자료형을 맞춰주기 위해 10을 float형으로 변환하여 비교한다.
float f = 0.1f;
double d = 0.1;
double d2 = (double)f;
10.0 == 10.0f; // true
0.1 == 0.1f // false;
f = 0.10000000149011612;
d = 0.10000000000000000;
d2 = 0.10000000149011612;
d == f; // false
d == d2; // false
d2 == f; // true
(float)d == f; // true
위의 결과는 어떻게 된것일까?
똑같은 0.1 이지만 float와 double의 값이 다른 것을 볼 수 있다.
10.0f는 오차없이 저장할 수 있는 값이라 double형으로 변환해도 오차가 없다.
하지만 0.1f는 저장할 때 2진수로 변환하는 과정에서 오차가 발생한다.
double 타입의 상수인 1.0 도 오차가 발생하지만, float보다 적은 오차가 발생해서 값이 달라지는 것이다.
또 float를 double로 형변환한다고 해도 가수의 빈자리를 0으로 채울 뿐이라 오차가 적어지진 않는다.
그래서 d2와 f가 같은 것이다.
double을 float로 형변환하면 어느정도의 오차를 무시하고 두 타입의 값을 앞에서 몇 자리만 잘라서 비교해서 올바른 결과를 얻을 수 있다.
일전의 내용에서 String은 클래스 형이라 새로운 객체를 생성하는 것이라고 배웠다.
String str = new String("abc");
처럼 생성해야 하는 객체를 편의를 위해
String str = "abc";
처럼 편의를 위해 간단히 표현하는 것이다.
그래서 String을 == 연산자로 비교하게 되면 같은 내용이지만 다른 객체 이기 때문에 false를 얻게 된다.
이를 위해 String은 equals() 메소드를 이용해야 한다.
x | y | x||y |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
OR 연산의 테이블 표 이다.
논리 연산자의 특징은 효율적인 연산을 한다.
알다시피 두 피연산자중 한 피연산자만 true이면 true의 결과를 얻는다.
두 피연산자 중 한 피연산자가 true면 전체 연산 결과가 true이기 때문에, 좌측 피연산자가 true이면 우측 피연산자의 값은 평가하지 않는다.
x | y | x&&y |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
AND 연산은 반대로
좌측 피연산자가 false라면 우측 피연산자의 값은 평가하지 않는다.
그래서 같은 조건식이라도 피연산자의 위치에 따라서 연산속도가 달라질 수 있다.
비트 연산자는 아직 비트 마스킹과 관련하여 지식이 부족하기 때문에,
조만간 알고리즘 파트에서 한번에 정리하리라..!