이 장들은 다른 언어와 비슷한 부분히 많고 대부분 아는 내용이기 때문에 평소에 알면 좋을 것 같은 내용들로 한번에 정리했습니다.
왜 그럴까?
실수의 2가지 표현방식
1. 고정 소수점(fixed point) 방식
2. 부동 소수점(floating point) 방식
고정 소수점 방식
- 위 그림과 같이 32bit를 고정소수점 방식으로 표현하면 다음과 같이 표현할 수 있다
=> 정수부와 소수부의 자릿수가 크지 않으므로 표현할 수 있는 범위가 좁다
부동 소수점 방식
- 위 그림과 같이 가수부와 지수부로 나누어서 실수를 표현하고 매우 큰 범위의 실수까지 표현할 수 있기 때문에 많은 시스템에서 부동 소수점 방식을 사용한다.
IEEE 754 표준에 따른 float 부동 소수점 방식
IEEE 754 표준에 따른 double 부동 소수점 방식
하지만 부동 소수점 방식은 10진수를 정확하게 표현할 수는 없다.
=> 그런 이유로 float는 6자리까지, double은 15자리까지 정도를 정확하게 표현 할 수 있음
+) 그러면 왜 C랑 C++은 기본적으로 유니코드가 아닌 아스키 코드를 제공할까?
- 간단함: 7비트 (확장된 경우 8비트) 만을 사용하기 때문에 메모리 사용이 효율적이다
- 호환성: 아스키 코드는 많은 컴퓨터 시스템과 통신에서 오랫동안 사용되어 왔기 때문에 거의 모든 시스템과 호환된다
하지만 최근에는 많은 기술 및 플랫폼에서 유니코드를 표준으로 채택하고 있기 때문에 국제화, 지역화 작업이 용이하여 유니코드를 채택하는 경우가 더 많다
타입변환의 2가지 종류
1. 묵시적 타입 변환
2. 명시적 타입변환
묵시적 타입변환
- 연산이나 대입과정에서 컴파일러가 자동으로 해주는 타입변환
- 손실이 최소화 되는 방향으로 타입변환을 해준다
int num3 = 9876543210L; long num4 = 9876543210L;
위와 같은 코드처럼 범위를 넘어가서 오류가 생기는 타입변환의 경우에는 리터럴의 마지막에 접미사를 추가해 줘야 한다
명시적 타입변환
- 사용자가 타입캐스트 연산자
(변환할 타입) 변환할데이터
를 작성하여 타입 변환
class A {}
class B extends A {}
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println(a instanceof A); // true
System.out.println(b instanceof A); // true
System.out.println(a instanceof B); // false
System.out.println(b instanceof B); // true
}
일반적인 break 문은 단 하나의 반복문만을 빠져나가게 해주는데 여러 반복문이 중첩된 상황에서 한 번에 모든 반복문을 빠져나가거나, 특정 반복문까지만 빠져나가고 싶을 때 어떻게 하지?
반복문에 이름(label)을 설정해서 break 키워드 다음 해당 이름을 명시해서 빠져나가자 !
allLoop :
for (int i = 2; i < 10; i++) {
for (int j = 2; j < 10; j++) {
if (i == 5) {
break allLoop;
}
System.out.println(i + " * " + j + " = " + (i * j));
}
}
/*
출력결과: i가 4까지만 출력됨
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
2 * 5 = 10
...
4 * 6 = 24
4 * 7 = 28
4 * 8 = 32
4 * 9 = 36
위와같이 이름(label)은 가리키고자 하는 반복문의 키워드 바로 앞에 위치해야 한다
(이름과 반복문의 키워드 사이에 명령문이 존재하면, 컴파일러가 오류를 발생시킴)
자바 프로그램이 실행되면, JVM은 운영 체제로부터 해당 프로그램을 수행할 수 있도록 필요한 메모리를 할당받는다
이렇게 할당받은 메모리를 JVM은 용도에 따라 아래와 같이 구분하여 관리한다
메소드(method) 영역
- 자바 프로그램에서 사용되는 클래스에 대한 정보와 함께 클래스 변수(static variable)가 저장되는 영역
- JVM은 자바 프로그램에서 특정 클래스가 사용되면 해당 클래스의 클래스 파일(*.class)를 읽어들여, 해당 클래스에 대한 정보를 메소드 영역에 저장한다
힙(heap) 영역
- 자바 프로그램에서 사용되는 모든 인스턴스 변수가 저장되는 영역
- JVM은 자바 프로그램에서 인스턴스가 생성되면, 해당 인스턴스의 정보를 힙 영역에 저장한다
- 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다
스택(stack) 영역
- 자바 프로그램에서 메소드가 호출될 때 메소드의 스택 프레임이 저장되는 영역
- JVM은 자바 프로그램에서 메소드가 호출되면, 메소드의 호출과 관계되는 지역 변수와 매개변수를 스택 영역에 저장한다
- 스택 영역은 메소드의 호출과 함께 할당되며, 메소드의 호출이 완료되면 소멸합니다.
- 이렇게 스택 영역에 저장되는 메소드의 호출 정보를 스택 프레임(stack frame)이라 부름
- 스택 영역은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당되고 LIFO 방식을 사용함
왜 이렇게 나누지?
배열은 아래와 같이 선언과 생성을 동시에 할 수 있다.
타입[] 배열이름 = new 타입[배열길이];
타입[] 배열이름 = {1, 2, 3};
arr.length
를 통하여 배열의 길이를 구할 수 있다.
// 가변 배열 선언
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[4];
arr[2] = new int[1];
// 가변 배열 선언과 동시에 생성
int[][] arr = {
{10, 20},
{10, 20, 30, 40},
{10}
};
int[] arr3 = Arrays.copyOf(arr1, 10);
int [] arr3 = arr1
int[] arr = new int[]{1, 2, 3, 4, 5};
for (int e : arr) {
System.out.print(e + " ");
}
Enhanced for문은 배열의 값을 참조할 때만 사용해야하며 값을 변경할 때는 사용할 수 없다.
int[] arr1 = new int[]{1, 2, 3, 4, 5};
int[] arr2 = new int[]{1, 2, 3, 4, 5};
for (int i = 0; i < arr1.length; i++) {
arr1[i] += 10;
}
for (int e : arr2) {
e += 10;
}
// 실행결과
// 11 12 13 14 15
// 1 2 3 4 5
=> Enhanced for문에서 사용되는 배열요소는 배열요소의 복사본이기 때문