3장 - 연산자

·2022년 11월 30일
0

자바의 정석

목록 보기
5/12
post-thumbnail

연산자

연산을 수행하는 기호.
피연산자는 당연히 연산을 당하는 대상이라고 생각하믄 된다.

  • 연산자 : 연산을 수행하는 기호 (-, +, /, % ...)
  • 피연산자: 연산자의 작업 대상(변수, 상수, 리터럴, 수식...)

연산자는 연산을 수행하고 나서 반드시 하나의 결과값을 반환한다.
반대로 말하면 연산 결과를 반환하지 않으면 연산자가 아니라고 보믄 된다. 예를 들면 괄호같은거?

1. 연산자의 종류

  1. 산술 연산자
    • 사칙연산, 나머지 연산
  2. 비교 연산자
    • 대소 비교, 같은지 다른지
  3. 논리 연산자
    • 그리고, 또는 << 얘들 갖고 조건들을 연결해준다.
  4. 대입 연산자
    • 우변의 값을 좌변에 저장한다. 우선순위가 낮다.
  5. 기타
    • 형변환 연산자, 삼항 연산자 등

5개나 되내.. 쓰벌 저렇게 ㅈㄴ 많은 연산자들을 또 다양허게도 분리한다..

피연산자의 개수로 연산자들을 분리하는데, 피연산자의 개수가 하나면 단항 연산자, 두개면 이항 연산자, 세개면 삼항 연산자라고 부른다. 이렇게 분리하는 이유는 연산자의 우선순위 때문이래~

2. 연산자의 우선순위

  1. 산술 > 비교 > 논리 > 대입. 대입 연산자는 연산자 중에서 우선순위가 가장 낮다.
  2. 단항 > 이항 > 삼항
  3. 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽

추가)
1. 쉬프트 연산자(<<)는 덧셈 연산자보다 우선순위 낮음.
2. 비트 연산자(&)는 비교 연산자(==)보다 우선순위 낮음.
3. 논리연산자(&&, ||) 중에서 &&가 ||보다 우선순위가 높다.

3. 산술 변환

이항 연산자는 두 피연산자의 타입이 일치해야 연산이 가능하다.

int i = 10;
float f = 20.0f;

float res = f + (float)i; // 형변환을 통한 두 타입 일치시키기.
float res = f + i; // 컴파일러에 의해 자동형변환 일어난다.

위의 예시와 같이, 작은 값을 더 큰 그릇에 넣는건 자동적으로 이루어진다.

  1. 두 피연산자의 타입을 같게 일치시킨다(큰 타입으로 통일)
  2. 피연산자의 타입이 int보다 작다면, int로 자동 변환된다.

산술 변환은 피연산자의 값손실을 최소화하기 위해서 일어난다.

4. 증감연산자.

전위형, 후위형 알면 되는데 걍 증가 후에 대입하냐 대입 후에 증가하냐 이 차이당

j = ++i;
이 식은

++i;
j = i;
이 둘을 합친거다.

j = i++;
이 식은

j = i;
i++;
이 둘을 합친거다.

추가적으로 당연한 얘기지만.. 부호 연산자는 boolean형, char형을 제외한 기본형에만 사용이 가능하다.


산술 연산자

사칙 연산자나머지 연산자로 이루어져있다.

1. 사칙 연산자 +, -, *, /

수학시간이당~
주의할 점은 피연산자가 정수인 경우, 나누는 수로 0을 사용할 수 없다

덧셈 연산자 예시

byte a = 10;
byte b = 20;
byte c = a + b;

System.out.println(c);

이렇게 하면 오류가 발생한다~ 와우 더해도 byte 범위 안인데 왜일까?
외냠연 위에서 말했듯, int보다 작은 수들끼리 연산을 하면, int로 변환되기 때문이다.
a + b끼리 연산하면 byte + byte = byte가 아니라
int + int = int가 되어, 보다 작은 byte 안에 들어갈 수 없게 된다.
고치면
byte c = (byte)(a + b)로 캐스팅 해주면 된다!

byte a = 10;
byte b = 30;
byte c = (byte)(a * b);

System.out.println(c);

이렇게 해도 오류가 발생한다~ 는 뻥이고 오류는 안나는데 300이 아니라 값손실이 일어난 44가 출력된다.
왜냐? 이번엔 둘을 곱한 수가 byte의 범위(-128 ~ 127)을 벗어났기 때문이다~ 잘 출력하려면 c와 곱한 결과를 int로 캐스팅해주면 되겠다~!

다시한번 말하지만
기존의 값을 최대한 보존할 수 있는 타입으로 형변환되며, 컴파일러는 값손실이 나지 않을 때만 자동형변환을 해준다.

int a = 1_000_000;
int b = 2_000_000;

long c = a * b;

sout(c);
결과 -어쩌고저쩌고

외 또 값손실이 났을까?
이유는 int int = int이기 때문이다 데박~
a
b가 계산이된 시점에서 이미 int형 범위가 벗어난 결과값이 int로 저장되어있고, 큰 그릇인 long c에 넣어도 값손실이 일어난 int값이 들어가있기 때문이다.
그렇다면 곱하기 연산을할 때, 둘 중 하나를 long으로 캐스팅해주면 자동형변환이 일어나 둘 다 long이 되고, long * long = long으로 정상적인 값이 나오게 된다

1번 케이스
byte b = 100;
byte b = (byte)100;
잘 된다! 데박적.

2번 케이스
int i = 100;
byte b = i;
안된다! 미쳣다

3번 케이스
byte b = 1000; // 에러 발생
byte b = (byte)1000; // 값손실, 그래도 돌아가긴 해~

왜 둘 다 같은 값인데 1번 케이스는 되고, 2번 케이스는 안될까?

1번 케이스는 리터럴 상수로, 컴파일러가 얘가 byte 범위 내부의 값이라는걸 확실히 인지하고, byte로 자동형변환을 해줘서 가능하다.

2번 케이스의 경우, 변수 i에 들어있으므로 컴파일러가 변수 안에 어떤 값이 들어 있는지 확인할 수 없어 자동형변환이 일어나지 않았기 때문에 에러가 발생한다. 단순히 4byte인 int형을 1byte인 byte에 넣으려 하네? 꺼지셈~ 하고 에러 발생.

3번 케이스의 경우, 같은 값을 넣었는데 1번은 돌아가지도 않고, 2번은 값손실이 일어났지만 출력이라도 되는 걸까?
당연히 1번은 byte의 범위를 벗어났기 때문에 형변환이 일어나지 않았고,
2번은 수동으로 형변환을 해줬으니 값손실이 발생한 채로라도 출력이 되는거다.

2. 반올림 - Math.round()

실수를 소수점 첫째 자리에서 반올림한 정수를 반환한다.

long res = Math.round(4.52);
res에는 5가 저장되어 있다.

원하는 자리에서 반올림하려면, 10^n을 곱한 후 나온 결과 값을 10^n으로 나눠주자.


비교 연산자

연산 결과는 true, false로만 반환한다.

1. 대소비교 연산자 <, >, <=, >=

boolean형을 제외한 나머지 기본형에 다 사용 가능, 참조형에는 사용 불가.

2. 등가비교 연산자 == !=

기본형, 참조형 모두 사용 가능!

2.1 문자열의 비교

문자열을 비교할 땐 '==' 대신 equals() 메서드를 사용하는게 좋다.

String str1 = "abc";
String str2 = "abc";

if (str1 == str2) {
	return true;
}

if (str1.equals) {
	return true;
}
둘 다 true를 얻을 수 있당

String str1 = new String("abc");
String str2 = new String("abc");

if (str1 == str2) {
	return true;
}

if (str1.equals) {
	return true;
}
'=='로 비교한건 false, equals()로 비교한건 true를 뱉는다

둘 다 같은데 왜~? 할 수 잇지만
두번 new로 생성한건 서로 다른 객체라서 ==로 비교 시 내용은 같지만, 다른 값으로 인식한다.
equals()는 객체가 달라도, 내용이 같으면 true를 반환하니 잘 기억해두자.
대소문자 구분 없이 비교하고싶다면, equalsIgnoreCase() 메서드를 사용하자.

논리 연산자

둘 이상의 조건을 '그리고(&&)'나 '또는(||)'으로 연결하여 하나의 식으로 표현하도록 한다.

그리고(and, &&)는 모든 조건이 맞아야하고, 또는(or, ||)는 여러 조건중 하나만 맞으면 다 맞다고 친다~
&&가 ||보다 우선순위가 높다~

그 외의 연산자

1. 조건 연산자 ?:

삼항 연산자는 조건 연산자 하나 뿐이다

  • if 조건문을 보다 간결히 표현할 수 있다
  • 조건 연산자의 결합 규칙은 오른쪽에서 왼쪽이다

res = x > 0 ? 1 : (x == 0 ? 0 : -1);

괄호가 있어서가 아니라, 조건 연산자의 결합 규칙은 오른쪽에서 왼쪽이라
x == 0 ? 0 : -1을 먼저 처리하고, 그 값을 갖고 외부의 삼항연산자를 진행하면 된다.

2. 대입 연산자 = op=

변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장할 때

  • 연산자들 중 가장 낮은 우선순위를 갖고 있어 가장 나중에 수행된다.
  • 진행 방향은 오른쪽에서 왼쪽이다.

2-1 lvalue와 rvalue

left-value, right-value 왼 오 구분은 할 줄 안다~

rvalue는 변수뿐만 아니라, 식, 상수 등이 모두 가능하다.
lvalue는 변수처럼 값을 변경할 수 있는것만 가능하다.

profile
어?머지?

0개의 댓글