5장. 계산을 하고 싶어요

공부하는 감자·2023년 11월 27일
0

자바의 신 3판

목록 보기
5/30

들어가기 전

『자바의 신 3판』 을 읽고 내용 정리 및 공부한 내용을 정리한 글입니다.
서적: 자바의 신 3판 구입처

내용 정리

기본 자료형을 제외한 참조 자료형은, 항상 예외가 되는 String이라는 클래스만이 + 연산이 가능하다.

다시 말해서, 계산을 위한 산술 연산자는 기본 자료형 중에서 boolean을 제외한 나머지 타입에서 사용할 수 있다.

연산자의 종류

대입 연산자 Assignment Operator

  • =

산술 연산자 Arithmetic Operator

  • + (additive operator, 더하기 연산자)
  • - (subtracation operator, 빼기 연산자)
  • * (multiplication operator, 곱하기 연산자)
  • / (division operator, 나머지 연산자)
    • 나누기를 할 때에는 모든 타입을 float 나 double 형으로 변경하고 실행해야 소수형으로 결과가 나온다.
    • 자바는 계산하는 두 값이 정수형이더라도, 결과가 소수형이면 알아서 소수형으로 결과가 나오지 않는다.
  • % (remainder operator, 나누기 연산자)
    • 나누기 연산자가 몫을 반환하고, 나머지 연산자가 나머지를 반환한다.
    • 어떠한 값이 N의 배수인지 아닌지 확인하고 싶을 때 사용할 수 있다.

복합 대입 연산자 Compound Assignment Operator

산술 연산자와 대입 연산자를 붙여 사용하면, 연산 후 결과를 바로 대입할 수 있다.

  • +=, -=, *=, /=, %=

단항 연산자

하나의 피연산자를 갖는 연산자이다.

  • + (Unary plus operator, 단항 플러스 연산자)
    • 숫자나 변수 앞에 붙이면 “변수×(1)변수\times(1)”를 의미하며, 양수를 표현한다.
    • 붙이지 않아도 양수이기 때문에, 숫자가 양수라는 걸 명시적으로 보여줄 때 사용한다.
    • ex) int a = +5
  • - (Unary minus oprator, 단항 마이너스 연산자)
    • 숫자나 변수 앞에 붙이면 “변수×(1)변수\times(-1)”를 의미하며, 음수를 표현한다.
    • ex) int a = -5;
  • ++ (Increment operator, 증가 연산자)
    • 전위와 후위를 구분한다.
    • 앞(전위)에 붙이면 그 변수를 참조하기 전에 1을 더한다.
    • ex). System.out.println(++2); → 3 출력
    • 뒤(후위)에 붙이면 그 변수를 참조한 후에 1을 더한다.
    • ex). System.out.println(2++); → 2 출력
  • -- (Decrement operator, 감소 연산자)
    • 전위와 후위를 구분한다.
    • 앞(전위)에 붙이면 그 변수를 참조하기 전에 1을 뺀다.
    • ex). System.out.println(--2); → 1 출력
    • 뒤(후위)에 붙이면 그 변수를 참조한 후에 1을 뺀다.
    • ex). System.out.println(2--); → 2 출력
  • ! (Logical complement operator, 논리 부정 연산자)
    • boolean 타입에서만 이 연산자를 사용할 수 있다.
    • boolean 값 앞에 붙여주면, 그 결과가 반대가 된다.
    • ex) !true → false

비트 연산자

비트 연산자는 부록에서 상세히 설명되어 있습니다.
아래는 부록을 정리한 내용입니다.

비트 연산자는 비트 단위로 데이터를 처리할 때 사용한다. C언어를 사용할 때에는 이 비트 연산을 많이 했지만, 자바에서는 API가 풍부하게 제공되므로 이 비트 연산자를 사용할 일은 그다지 많지 않다.

하지만, CPU의 성능이 아주 느린 작은 장비에 들어가는 프로그램을 작성하거나, 암호화 작업과 관련된 작업을 할 때에는 조금이라도 메모리를 줄이고, 성능을 개선하기 위해서 필요할 수도 있다.

즉, 유지보수해야하는 누군가가 만든 코드에 비트 연산이 있을 수도 있기 때문에 알아두어야만 한다.

컴퓨터는 2진수이다.

컴퓨터의 기본적인 처리는 0과 1, 꺼져 있는 것과 켜져 있는 것으로 나뉜다. 1 bit라는 것은 0과 1로 표시할 수 있는 하나의 단위다. 그리고, 8 bit는 1 byte가 된다.

8 비트로 나타낼 수 있는 수는 282^8가지, 총 256가지가 된다.

여기서 8 비트를 4자리씩 끊으면 4비트 두 개로 표현할 수 있고, 각 4자리는 16진수로 표현이 가능하기 때문에 16진수 두 개로 8비트, 즉 1 바이트를 표현할 수 있다.

2진수 8자리로 표현하는 것보다, 16진수 2자리로 표현하는 것이 훨씬 효율적이다.

2진수를 16진수로 표현한 표.
숫자 10부터는 알파벳 A부터 시작한다.

10진수2진수16진수10진수2진수16진수
000000101010A
100011111011B
200102121100C
300113131101D
401004141110E
501015151111F
601106
701117
810008
910019

bitwise 연산자

두 개의 숫자를 비교하는 연산자.

  • &: AND 연산
    • 두 숫자의 각 bit 위치별 값이 동일한지를 비교한다.
    • 두 개의 값을 비교해서 모두 1일 경우에만 1이고 나머지는 모두 0이 된다.
  • | : OR 연산 (inclusive OR 연산이라고도 부름)
    • 두 숫자의 각 bit 위치별 값을 비교한다.
    • 두 개의 값을 비교해서 둘 중 하나라도 1일 경우에 1이 된다.
  • ^: XOR 연산 (exclusive OR 연산이라고도 부름)
    • 두 숫자의 각 bit 위치별 값을 비교한다.
    • 두 값이 다르면 1이 되고, 두 값이 같으면 0이 된다.

Not 연산자

  • ~ : unary 연산 (틸드라고 읽는다.)

비트 연산자 중 유일한 단항 연산자다. 각 bit의 값을 반대로(0은 1, 1은 0) 바꿔버린다.

bit shift 연산자

비트를 이동하는 연산자. 왼쪽에 있는 값을 오른쪽에 있는 값만큼 비트를 이동시킨다.

  • << : 왼쪽 이동
    • 비트값들을 왼쪽으로 한 칸씩 옮긴 후 이동한 다음에 빈 공간에는 모두 0으로 채운다.
    • 만약 모든 값이 0인 경우에는 모든 비트 값이 0이 되므로 더 이상 좌측으로 옮겨봤자 소용이 없게 된다.
  • >> : 오른쪽 이동
    • 비트값들을 오른쪽으로 한 칸씩 옮긴 후 이동한 다음에 빈 공간에는 모두 0으로 채운다.
    • 마찬가지로 계속 옮기다 보면 0이 된다.
    • 음수를 비트 이동하게 되면 이동된 빈 자리는 0이 아닌 1로 채워진다.
  • >>> : 부호 상관 없는(unsigned) 오른쪽 이동
    • 부호를 신경쓰지 않는다.
    • 즉, 위에서는 음수일 경우 좌측의 빈 자리를 1로 채우지만 이 연산자는 그러한 작업을 수행하지 않는다.

비교 연산자

모든 비교 연산자의 결과는 반드시 boolean이다. 해당 “조건에 맞으면 true, 그렇지 않으면 false”가 된다.

1. 등가 비교 연산자 Equality Operator

💡 기본 자료형과 참조 자료형, 즉 모든 타입에서 사용할 수 있다. 기본 자료형은 같은 종류끼리 비교가 가능하다 (숫자형끼리, boolean끼리)

종류

  • == (equal to, 같음)
  • != (not equal to, 같지 않음)
// 아래와 같은 자료형이 있을 때
char charVal = 'a' // ASCII 97
int intVal = 1;
double doubleVal = 1.0;

// 아스키코드 97 = 'a'이기 때문에 true이고,
// 같은 숫자형은 int와 double도 true로 나온다.
System.out.println(97 == charVal);       // true
System.out.println(intval == doubleVal); // true

2. 대소 비교 연산자 Relational Operator

💡 boolean을 제외한 기본 자료형, 그 중에서도 숫자형에서만 사용 가능하다.

종류

연산자true 조건
>a < ba가 b보다 작을 때
<a > ba가 b보다 클 때
<=a <= ba가 b와 같거나, b보다 작을 때
>=a >= ba가 b와 같거나, b보다 클 때

논리 연산자 Conditional Operator

연산자명칭true 조건
&&AND 결합. Conditional AND두 개의 조건이 모두 true일 때에만 true

그리고, 숫자에 사용하면 비트 연산을 수행하지만 boolean 타입 사이에 사용하면 논리 연산을 수행해주는 연산자들이 있다.

연산자true 조건
&두 값이 모두 true일 때에만 true
^두 값이 서로 다를 경우에는 true. 모두 true이거나, false이면 false

&과 &&, |과 ||는 같아보이지만 실제 연산하는 방식에서는 차이가 있다.

&&의 경우 좌측에 있는 연산이 false 이면 우측에 있는 연산을 수행하지 않는다. 왜냐하면 두 개의 조건이 모두 true 여야만 true이기 때문에, 앞의 연산이 false이면 뒤의 연산을 수행할 필요가 없기 때문이다.

하지만 &의 경우는 좌측 연산 결과와 우측 연산 결과를 비교해야만 하기 때문에 모든 연산을 수행한다.

때문에 &&와 ||를 사용하는 것을 권장한다.

삼항 연산자 Conditional Operator ? :

= 왼쪽에 있는 변수에 값을 할당할 때 사용한다. 이때, 대입하는 값은 변수와 같은 타입이어야 한다.

변수 = (결과가 boolean인 조건식) ? true일 때 값 : false일 때 값

instanceof 연산자

유일하게 자바의 예약어로 되어있는 연산자이며, 상속의 개념을 알고 있어야 하므로 10장에서 다시 설명한다.

연산자의 우선순위

각 연산자에는 우선 순위가 있어서, 해당 순위 별로 먼저 계산해준다. 원하는 연산부터 하도록 하고 싶다면 괄호를 사용한다.

괄호 예시: (1+2)*3

구분연산자우선 순위
단항 연산자++ -- + - ! ~1
산술 연산자* / %2
+ -3

형 변환 Casting

서로 다른 타입 사이에 변환하는 작업을 하는 것을 말한다. 자바의 형 변환은 기본 자료형과 참조 자료형 모두 괄호로 묶어주면 된다.

  • 기본 자료형 → 참조 자료형, 혹은 참조 자료형 → 기본 자료형으로의 형 변환은 절대 안된다.
  • 그렇지만 숫자 값을 참조 자료형으로 변경할 수 있는 방법은 존재한다.

기본 자료형의 형변환

boolean 타입은 숫자로 변환할 수 없기 때문에 형 변환이 불가능하다.

바이트 크기가 커지는 캐스팅을 할 경우에는 별도로 해줄 것이 없다. 명시적으로 형 변환을 해주지 않아도 자바에서 자동으로 형 변환 해주기도 한다.

하지만, 바이트 크기가 작아지는 캐스팅을 할 경우에는 앞의 바이트를 버려버리기 때문에 데이터의 손실이 일어난다.

일례로 실수 타입을 정수 타입으로 강제 타입 변환하면 소수점 이하의 데이터들이 버려진다.

범위의 순서

byteshort, charintlongfloatdouble

아래 내용은 참고 사이트에서 일부 발췌했다. 이 블로그에 설명이 자세히 되어 있다.

long 과 float 타입 크기

long 타입은 8바이트이고 float은 4바이트이기 때문에 따라서 float가 long 보다는 작은 타입이 되어야 하지만, 범위를 보면 long 보다 float이 더 크다고 되어있다.

왜냐하면 일반적으로 메모리 설계상 정수 타입보다 실수 타입이 더 크게 되어 있기 때문이다.

4바이트 float이 더 큰 수를 표현할수 있는 이유는 바로 부동소수점 방식으로 표현하기 때문이다.

부동 소수점 방식에서는 지수부와 가수부를 나누고, 가수부에는 실제 값을 지수부에는 2제곱을 얼마나 곱할지 표현하기 때문에 수의 표현 범위는 long 타입보다 더 커지게 되는 것이다.

int 와 float 형 변환

int → float 로 형 변환하는 경우, 정밀도의 손실이 일어날 수 있다고 한다. 자세한 것은 위 인용의 참고 사이트 참고.

타입 별 사용 가능한 연산자

구분연산자 명칭연산자
결과가 boolean인 경우숫자 비교 연산자<, <=, >, >=
숫자 동등 연산자==, !=
결과가 int나 long인 경우기본 사칙 연산자+, -, *, /, %
증감 연산자++, --
비트 연산자&,
기타 연산자삼항 연산자? :
형 변환 연산자(타입)
문자열 더하기 연산자+

정수형

자바에서 제공하는 모든 연산자를 사용할 수 있다.

소수형

소수형은 비트 연산이 불가능하다.

boolean 타입

구분연산자
동등 연산자==, !=
조건적 논리 연산자&&,
논리 연산자!, &,
삼항 연산자? :
문자열 더하기 연산자+

참조 자료형

참조 자료형은 + 연산만 가능하다.

연산자설명
+해당 클래스에 있는 toString() 메소드의 결과와 그 연산자 뒤에 있는 문자열을 더한다.

정리해 봅시다.

Q. 값을 할당할 때 사용하는 연산자의 기호는 무엇인가요?

Me: =

Q. 기본적인 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지를 계산할 때 사용하는 연산자의 기호는 순서대로 각각 무엇인가요?

Me: +, -, *, /, %

Q. += 는 무엇을 할 때 사용하는 연산자 인가요?

Me: 좌측 변수와 우측의 값을 더한 후 좌측 변수에 대입해준다.

Q. 연산의 순서를 모르거나 확실히 하고 싶을 때에는 어떤 기호를 사용해야 하나요?

Me: 소괄호 ()

Q. ==와 !=의 차이는 무엇인가요?

Me: 두 값을 비교해서 ==는 같을 경우 true를, !=는 다를 경우 true를 반환한다.

Q. <와 <=의 차이는 무엇인가요?

Me: <는 작은지, <=는 작거나 같은지를 검사한다.

Q. ! 연산자는 어떤 타입에 사용 할 수 있나요?

Me: boolean 타입

Q. ? : 로 표시하는 삼항 연산자의 ?와 : 뒤에 명시해 주는 값은 무엇을 의미 하나요?

Me: 좌측 변수에 대입할 값을 말한다. 연산의 결과에 따라 ? 뒤는 true일 경우, :는 false일 경우 대입된다.

Q. 자바는 형변환을 한다고 했는데, short의 값을 long에 할당할 때에는 어떤 것을 해 주어야 하나요?

Me: 하지 않아도 괜찮지만, 명시적으로 지정해주고 싶다면 (long) 을 사용한다.

Q. 반대로 long값을 short에 할당할 때에는 어떤 것을 해 주어야 하나요?

Me: (short)

Q. 위의 두 문제에서 어떤 경우가 기존 값이 사라지고, 엉뚱한 값으로 바뀔 수 있나요?

Me: long값을 short에 할당했을 경우

질문

💡 책에 있는 내용이 아닙니다.

책을 읽으며 설명이 더 필요하거나, 추가로 궁금한 점에 대해 질문 형식으로 작성 후, 답을 구해보고 있습니다.
참고한 사이트나 영상은 [출처]로 달아두었으며, 오류 지적은 언제나 환영합니다.

Q. ~(틸드) 연산자를 char에 썼을 경우

'a'는 아스키코드 97이므로, int 값 97에 ~ 연산자를 쓴 것과 동일한 결과가 나옴을 확인할 수 있다.

Q. byte 와 char 간의 형 변환은 어떻게 되나?

char는 아스키코드와 유니코드를 표현할 목적으로 사용되기 때문에, 음수는 표현하지 않는다. 그러므로 둘 사이에서도 자동 형 변환은 일어나지 않는다.

명시적 형 변환은 사용할 수 있으며, char → byte 는 char의 양수 범위가 byte 범위를 벗어나면 앞의 비트를 버리고 들어갈 것을 예상해볼 수 있다.

  • byte 양수를 형 변환할 경우, 잘 된다.
  • 그렇다면 byte 음수를 char로 형 변환하면?
    • 먼저, 자동 형 변환이 안되는 것부터 확인했다.
    • 그 후, 각각 -10, -100을 형 변환 해봤는데 모두 char가 ‘?’ 로 나오는 것을 볼 수 있었다.
    • 원래 물음표는 아스키코드 63에 해당하지만, 여기서는 없는 문자라는 뜻으로 출력된 것이다.

Q. short 와 char 간의 형 변환은 어떻게 되나?

서로 자동 형 변환은 불가능하고, 강제로 형 변환해주면 가능하다.

예제와 함께 확인 (이미지가 많아서 토글로 감춤)
먼저, 자동 형 변환은 지원하지 않는 것을 확인했다. ![](https://velog.velcdn.com/images/p0tat0_chip/post/f1e2a101-25de-464c-8ea0-f3785a93d49d/image.png)

위와 동일한 변수로 명시적 형 변환을 했을 경우엔 동작하는 걸 볼 수 있다.

short의 범위와 char의 범위가 일부 겹치기는 하나, 다른 부분도 존재하기 때문에 자동 형 변환은 지원하지 않는 것 같다.

char → short
1. char에 Char범위 MAX값을 설정한 후, short로 형 변환
2. char에 Short범위 MAX값을 설정한 후, short로 형 변환
3. char에 (Short범위 MAX + 1)값을 설정한 후, short로 형 변환

둘은 같은 16비트지만, char는 부호가 없고(unsigned) short는 부호가 있다. 따라서, 첫번째 결과는 Char의 최댓값을 넘어가므로 최소값으로 이동되어 최소값 32768-32768부터 3276732767을 더 간, 1-1을 출력한다.

두번째는 넘치지 않았으므로 값 그대로 출력되고, 세번째는 1이 넘쳤으므로 최소값이 출력된다.

short → char

short 에 음수를 넣고 char로 형 변환했다. 없는 문자라는 ‘?’가 출력되어서, int로 형 변환해서 값을 확인했다.

short 에 양수를 넣고 char로 형 변환하면, 숫자에 대응하는 char 값을 확인할 수 있다.

profile
책을 읽거나 강의를 들으며 공부한 내용을 정리합니다. 가끔 개발하는데 있었던 이슈도 올립니다.

0개의 댓글