0615. 배열과 연산자

hyunn·2021년 6월 17일
0

Java-basic

목록 보기
7/26
post-thumbnail

리터럴

  • 정수 - 100 4byte 100L 8byte

  • 부동소수점(실수) - 3.14 8byte 3.14f 4byte

  • 논리 - true false

  • 문자 - ‘A’, ‘가’

  • 문자열 - "ABC가각간”



배열

int[] arr = new int[2]; 

[ ][ ] 2칸짜리 배열 생성

배열 인스턴스와 레퍼런스

int[] arr = new int[3];
arr[2700] -> 2700번째메모리의미 -> [0][1][2] 
ㄴ int 배열의 reference(참조) 		ㄴ int배열의 instance(실례)
  • instance : 배열에서 생성된 객체의 메모리 주소
  • reference : 배열에서 특정 인스턴스에 접근하는 변수 ex. arr


연산자

산술연산자

/ * + - %(나눈 나머지)

값 + 값

값 = 피연산자 Operand : 리터럴, 변수 둘 다 올 수 있음

연산자 Opertor

연산자 우선순위

둘이 같은 레벨일 경우 먼저 나온 연산자 우선

(괄호)사용해서 실행 순서를 바꿀 수 있음

괄호: ()
후위 연산자: a++, a--
전위 연산자: ++a, --a, 단항 연산자(+, -)
, /, %
+, -
비트이동 연산자: <<, >>, >>>
관계 연산자: <, >, <=, >=, instanceof
등위 연산자: ==, !=
&
^
|
논리 연산자 AND: &&
논리 연산자 OR: ||
삼항 연산자: (조건) ? 값1 : 값2 //조건이 true면 값1 false면 값2
할당 연산자: =, +=, -=,
=, /=, %=, &=, ^=, |=, <<=, >>=, >>>=


기본 연산 단위

byte x = 5;
byte y = 6;

리터럴 5, 6 - 4byte 정수값

정수 리터럴은 기본이 4바이트지만 byte변수에 저장하는 것은 허락

byte z = 5 + 6;

리터럴끼리 산술한 결과도 리터럴로 간주

그 결과값이 변수의 범위 내의 값이면 허락

z = x + y; //컴파일오류

자바의 정수 연산은 최소단위가 4byte

정수변수에 대해 산술연산 수행시 그 변수 값이 4byte보다 작다면(byte -1, short-2)

임시로 4byte메모리를 만들어 연산 수행함

즉 z = x + y 연산에서 임의의 4byte 메모리에 x와 y를 각각 담아 연산 수행

연산결과 4byte >> z 메모리 1byte

결과가 메모리보다 커서 컴파일 오류 발생하는 것

위의 식들은 하나라도 리터럴이 있어서 허락이 발생하는 것이고 변수끼리의 식에서는 허락이 발생하지 않아 컴파일 오류가 발생한다

=> 숫자를 다룰때는 메모리가 큰 int를 사용하는 것이 편리하다

Data type과 연산자

모든 종류의 데이터에 모든 종류의 연산자를 사용할 수 있는건XX

Boolean type은 산술연산자 불가

문자열 type은 +를 문자열 연결 용도로만 사용가능

정수끼리의 논리는 불가능

연산의 결과 타입

연산을 수행한 후 결과값은 피연산자와 같은 타입

int + int -> 결과도 int

int x = 5, y = 2;

float z = x / y   //2.0

이미 int끼리의 연산으로 5/2=2라는 결과가 나온 상태에서 z에 대입되므로 값은 2.0이 된다

원하는 값을 얻기 위해서는 형변환을 해주면서 연산을 해야함

z = (float)x / (float)y		// 2.5

연산 결과는 피연산자의 타입과 같다

두 값을 계산했을 때 결과 메모리를 초과할 경우 값이 짤릴 수 있음

코드를 작성할 때 피연산자의 계산 결과가 피연산자의 메모리 크기를 벗어날 가능성이 있다면?

-> 처음부터 피연산자의 값을 더 큰 메모리에 담아서 연산을 수행



형변환 (type casting = type conversion)

변수나 리터럴을 다른 타입의 값을 바꾸는 것

!! 원래 변수의 타입을 바꾸는 것이 아님

내부적으로 변수에 들어 있는 값을 꺼내 지정된 타입의 임시 메모리를 만들어 저장

암시적 형변환 (implicit type conversion=casting)

자바의 최소 연산 단위는 int

int보다 작은 크기의 메모리 다룰 때 내부적으로 int로 자동형변환 수행 후 연산 수행

내부적으로 자동 형변환하는 것 = "암시적 형변환(implicit type conversion)"

규칙

byte + byte = int / short + short = int

byte + short = int / byte + int = int

int + long = long

long + float = float -> 8byte의 long이 float 처리되면서 데이터손실 발생

long + double = double

Boolean + int => 연산불가!

byte short -> int -> long -> float -> double

여러 연산자와 data type이 섞여있을 때 연산 우선순위따라 계산하는 순간에 형변환 일어남

!! 모든 값을 최종 결과타입으로 바꿔놓고 계산하지않음

명시적 형변환

저장하려는 메모리보다 더 큰 값일 경우

byte b;

b = 259; 
//컴파일 오류 -> 명시적 형변환을 통해 값을 지정해줌

b = (byte)259;

총 4byte 결과값 중 앞의 3byte가 잘리고 마지막 1byte만 저장됨

System.out.println(b); //3

형변환 하더라도 값이 소실되지 않을 경우에만 실시하는 것을 권장



관계연산자, 등위연산자

  • 관계연산자 : <, <=, >, >=

  • 등위연산자 : == 같음, != 다름

비교의 결과값은 true, false -> boolean값만 가능

Boolean r1 = a < b;  //true or false
int r2 = a < b;  //컴파일 오류

부동소수점 비교

double d1 = 987.6543;
double d2 = 1.111111;

System.out.println((d1 + d2) == 988.765411); // false

이유?

부동소수점 값을 연산할 때 IEEE 754 명세에 따라 작업을 수행한다. 그 과정에 값의 왜곡 발생

CPU나 OS, JVM의 문제XX

IEEE 754 명세에 따라 부동소수점을 처리하는 모든 컴퓨터에서 발생하는 문제

해결?

소수점 뒤에 붙은 극소수의 값을 무시하면 된다.

=> JVM이 자동으로 처리하지 않는다.

=> 다음과 같이 개발자가 직접 처리해야 한다.

double EPSILON = 0.00001;
System.out.println(Math.abs((d1 + d2) - (x + y)) < EPSILON);

미세오차 EPSILON 설정해서 비교할 두 값의 차가 오차보다 작음을 비교해주면 0으로 간주해 대충 같다고 간주

=> 오차를 제거한 후 비교

=> 다만 계산 결과를 절대값으로 만든 후에 오차 이하의 값인지 비교하라!

논리연산자

논리 연산자 : &&, ||, !(not), ^(XOR; exclusive-OR)

&& AND
|| OR
! NOT
^ XOR : 두 개의 값이 다를 때 true 1/ 같을때 false 0

논리연산자 && vs &

and 연산자의 경우엔 둘 중에 하나라도 false면 false

때문에 앞의 논리값이 false면 이미 결과값이 false임을 알 수 있음

or 연산자의 경우엔 하나라도 true면 결과값도 true

때문에 이미 앞의 논리값이 true면 뒤의 논리값까지 보지 않고도 결과값이 true임을 알 수 있음

이렇게 앞의 논리값으로 결과를 예측할 수 있으면 뒤의 논리값까지 수행하지 않는 것이 &&와 || 연산자

그래도 끝까지 연산을 수행하는 것이 &와 |

&&, ||

  • 앞의 피연산자의 값으로 결과를 알 수 있다면 뒤의 명령은 실행하지 않는다.

&, |

  • 앞의 피연산자로 결과를 알 수 있을 지라도, 뒤에 놓은 명령까지 모두 실행한다.
boolean a = false;
boolean b = false;
boolean r = a && (b = true);	//b가 true로 바뀌지 않음

a = false;
b = false;
r = a & (b = true);		//b가 true로 바뀜


비트연산

비트연산자 & | ^(xor) ~(not)

각 비트단위로 연산 수행

1 = true, 0 = false 로 간주하고 계산

정수값을 연산할 수 없는 && || ! 와 달리 정수를 비트로 변환시켜 연산 가능

int a = 0b0110_1100;
int b = 0b0101_0101;
System.out.println(a & b); //각 비트단위로 and연산 수행

a = 0000 0000 0000 0000 0000 0000 0110 1100
b = 0000 0000 0000 0000 0000 0000 0101 0101
--------------------------------------------
0000 0000 0000 0000 0000 0000 0100 0100 = 68

&를 이용해 % 연산처리

(값 % 2) == 0 => 짝수

(값 & 0x1) == 0 => 짝수

ㄴ 맨 뒤의 비트가 1인지만 확인하면 된다는 것

서로 비트가 다르다 = 값의 맨 마지막 값이 0이다-짝수 = 0&1 = 0 == 0 짝수!

어떤 값에 1을 연산시킨다는 뜻은 맨 끝의 1bit만 추출한단뜻

왜써? >> 비트연산이 그냥 %연산보다 계산속도가 빨라서

x % 2 -> x & 0x1(0b01) – 맨 끝의 1비트만 추출

x % 4 -> x & 0x3(0b11) – 맨 끝의 2비트만 추출

x % 8 -> x & 0x7(ob111) – 맨 끝의 3비트만 추출 - 4 2 1 다 더해도 7이니까
n으로 나눈 나머지를 구하는 것과 같음

//ex05.Exam0350 참고

연산의 응용 - 색상 변형

RGB

  • 파란색을 약간 빼기
	01100011 11000001 11101011
&	11111111 11111111 01010101
	01100011 11000001 00100001
  • 빨간색 강화하기
	01100011 11000001 11101011
|	10101010 00000000 00000000
	11101011 11000001 11101011

조건문과 비트연산

&&, ||, ! 의 피연산자(operand)는 반드시 Boolean, 계산 결과도 boolean

&, |, ^, ~(not) 의 피연산자는 정수, 계산 결과도 정수 // float - 컴파일오류



비트 이동 연산자 : >>, >>>, <<

<< 비트 이동 연산자

왼쪽으로 비트를 이동

오른쪽 빈자리는 0으로 채움

왼쪽 경계를 넘어간 비트는 자름

int i = 1;

System.out.println(i << 4);

0000[0000000000000000000000000001]
    [00000000000000000000000000010000] = 16

왼쪽 이동

1비트 이동은 곱하기 2 한 것과 같은 효과를 준다.

값을 배수로 증가시킬 때 곱하기 연산을 하는 것 보다

왼쪽 비트 이동 연산을 하는 것이 빠르기 때문에

실무에서는 이 비트 이동 연산을 자주 사용한다.

비트 이동 => '2**이동비트'를 곱한 것과 같은 결과를 만든다.

음수의 경우에는 음수부호비트도 같이 왼쪽으로 옮겨지므로 부호가 바뀜

음수를 왼쪽으로 이동시키는 것은 양수를 이동시키는 것과 같은 값


비트 이동의 유효범위

System.out.println(3 << 33); // 6
System.out.println(3 << 65); // 6
System.out.println(3 << 97); // 6

값 3 에 대해 33비트, 65비트, 97 비트를 이동하나 같은 값이 나오는 이유?

  • int 타입의 값에 대해 비트 이동을 할 때는 0 ~ 31까지만 유효

-> 4byte = 32bit 값이기때문에

만약 31을 넘는 경우 32로 나눈 나머지 값을 비트 이동으로 간주

  • long 타입의 경우 비트 이동은 0 ~ 63까지 유효

-> 8byte = 64bit 값이기때문에

만약 63을 넘는 경우 64로 나눈 나머지 값을 비트 이동으로 간주

// ex05.Exam0412.java 참고

비트이동의 최대 크기

int값은 4byte = 32bit 최대 32비트까지만 이동 가능한 것

그 이상의 값으로 이동시키면? -> 값을 32로 나눈 나머지만큼 이동하는 것

int 값  x << y = x << y`(=y & 0x1F = y % 32)

x << 1 = x << 33 (33%32=1) = x << 65 (65%32=1)

어짜피 큰 수를 줘도 최대 비트 범위 내에서만 이동하므로 범위내의 값을 주는게 나음


>> 비트 이동 연산자

왼쪽 쪽 빈자리를 원래 숫자와 같은 부호 값으로 채운다.

양수라면 0, 음수라면 1을 채운다.

오른쪽 경계를 넘어간 비트는 자른다.

int i = 105;

System.out.println(i >> 4);

[00000000000000000000000001101001]
[    0000000000000000000000000110]1001 => 6

오른쪽 이동

1비트 이동은 나누기 2 한 것과 같은 효과 (나누기 2하고 나머지 제거)

ex. n에 대해 x비트를 오른쪽으로 이동 = n / 2**x

소수점이 있는 경우 그 수 보다 작은 바로 밑 정수 값이 된다.

나누기 연산을 수행하는 것 보다 계산 속도가 빠르다.

실무에서는 나눗셈 연산이 비용(시간과 CPU 사용량)이 많이 들기 때문에

소수점 이하까지 정확하게 계산할 게 아니라면 오른쪽 비트 이동 연산자를 사용하여 주로 처리


>>> 비트 이동 연산자 사용법

오른쪽으로 비트를 이동, 왼쪽 빈자리를 음수 양수 상관없이 무조건 0으로 채움

오른쪽 경계를 넘어간 비트는 자름



비트연산자 응용

Yes/No 또는 true/false 값을 저장할 때 사용하면 메모리 절약할 수 있음

비트 연산자 사용 전

=> 각각의 상태를 별도의 변수에 저장해야 한다.

=> 8개의 데이터를 저장하기 위해 32바이트가 소요된다.

배열 이용 가능

boolean 배열을 JVM에서 다룰 때 각 boolean에 대해 1바이트 사용

=> 따라서 8개의 데이터를 저장하기 위해 8바이트를 사용

비트 연산자 사용 후

=> 4바이트 변수 한 개만 있으면 최대 32개의 데이터를 저장할 수 있음

비트를 활용한 true/false 설정

Q. 10개 항목에 대해 true/false 값 저장

1) Boolean b1, b2, …, b10;

2) Boolean[] arr = new boolean[10];

3) int state; -> 정수 메모리의 각 비트에 항목의 값(true(1)/false(0)) 저장
=> 4byte 만으로 32개 항목에 대해 값 저장 가능

다양한 데이터를 여러 개의 변수를 사용하지 않고도 true / false 두가지 만으로 표현할 수 있게됨

// ex05.Exam0450.java, ex05.Test01 참고



조건 연산자 => ? :

조건 ? 표현식1 : 표현식2

=> 조건이 참이면 표현식1 실행, 거짓이면 표현식2 실행

용어정리 : Statement 와 Expression

int a; -> statement

if( ) { } -> statement

a + 2 -> statement (문장) 
  ㄴ> 실행결과를 리턴 => Expression (표현식)
  • Expression 표현식 : 결과를 리턴하는 명령문

  • Statement 문장 : 명령문

  • statement 중에서 결과를 리턴하는 statement = expression



증감 연산자

전위연산자 pre-fix vs 후위연산자 post-fix

++x -> 전위연산자

변수 x의 값 증가시키고, 현재 위치에 변수값 적용

x++ -> 후위연산자

현재 위치에 변수값 적용하고, 변수 x의 값을 증가

후위/전위 연산자의 동작 이해

int i = 7;
int j = i++;

//컴파일러가 아래처럼 변환시켜 컴파일
int temp = i;
i = i + 1;
int j = temp;

임시저장소 temp 생성

전위/후위 연산자가 없다면 위와 같이 길게 코드를 작성해야함

컴파일할 때 위의 코드로 변환되어 컴파일되기는 함

왜?

연산자 우선순위에 따라 =할당연산자는 오른쪽의 모든 식이 완료되어야 진행

원래 식대로 진행하게되면 원하는 값이 나오지 않을 수 있다 (i++지만 ++i처럼 될수도)

그래서 컴파일러가 i++ 식을 길게 변환시켜 컴퓨터에 입력해 실행하도록 하는 것

int i = 7;
i = i++; 	

//->	
int temp = i;
i = i + 1;
i = temp;


할당(배정,대입) 연산자

+= -= *= /= %= &= |= ^= <<= >>= >>>=

+=문법

a = a + 7; = a += 7;

개발자를 위해 만든 단축 문법

실제 컴파일 시 컴파일러는 a+=7 문장을 a=a+7 문장으로 변환 후 컴파일

-> 연산자의 동작을 억지로 이해하려 하지말 것

-> 실제 어떤 문장으로 변환되는지를 아는 것이 문법 이해에 더 도움됨

0개의 댓글