른록노트
[Java] 자바 데이터 타입, 변수 그리고 배열 본문
목표
자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
학습할 것
- 프리미티브 타입 종류와 값의 범위 그리고 기본 값
- 프리미티브 타입과 레퍼런스 타입
- 리터럴
- 변수 선언 및 초기화하는 방법
- 변수의 스코프와 라이프타임
- 타입 변환, 캐스팅 그리고 타입 프로모션
- 1차 및 2차 배열 선언하기
- 타입 추론, var
자바의 타입은 크게 두가지 타입으로 나눌 수 있습니다.
- 기본 자료형(Primitive data type)
- 참조 자료형(Reference data type)
먼저 기본 자료형(프리미티브 타입)에 대해서 먼저 알아보겠습니다.
프리미티브 타입 종류와 값의 범위 그리고 기본 값
기본 자료형은 숫자와 boolean으로 분류 할 수 있고, 숫자에선 정수형과 소수형으로 나눠져 있습니다.
- 정수형
- byte
- short
- int
- long
- char
- 소수형
- float
- double
- 기타
- boolean
아래의 표는 기본 자료형 값의 범위와 기본값입니다.
타입 | 최소 | 최대 | 기본값 |
byte | -128 (-2^7) | 127 (2^7-1) | 0 |
short | -32,768 (-2^15) | 32,767 (2^15-1) | 0 |
int | -2,147,483,648 (-2^31) | 2,147,483,647 (2^31-1) | 0 |
long | -9,223,372,036,843,775,808 (-2^63) | 9,223,372,036,843,775,807 (2^63-1) | 0 |
char | 0 ('\u0000') (0) | 65,535 ('\uffff') (2^16-1) | \u0000 |
float | (2^-149) | ((2-2^-23)*2^127) | 0.0 |
double | (2^-1074) | ((2-2^-52)*2^1023) | 0.0 |
boolean | false | true | false |
byte는 8비트 - 1바이트
short는 16비트 - 2바이트
int는 32비트 - 4바이트
long은 64비트입니다. - 8바이트
제일 첫번째 비트는 부호 비트이고 MSB(Most Significant Bit - 최상위 비트)라고 말합니다.
* 자바 8 버전부터는 unsigned int / unsigned long이 추가되었습니다.
참고사이트 (gs.saro.me/dev?tn=361)
* JVM 내부에서는 전부 4바이트 크기로 만들어서 관리한다고합니다. 그러므로 기본 자료형을 사용할 때
4바이트보다 작은 타입에 대해서는 int를 사용하는게 성능에 조금이라도 도움이 될 것 입니다.
아래는 기본 자료형의 디폴트 값을 확인하기위한 코드입니다.
만약 지역 변수로 기본자료형의 기본값을 사용하려고 한다면 컴파일 에러가 날 것 입니다. 그래서 테스트 하기위해서는 인스턴스 변수나 클래스 변수, 매개변수를 사용해야 컴파일 에러가 발생하지 않습니다.
public class PrimitiveTypes {
byte aByte;
short aShort;
int anInt;
long aLong;
char aChar;
double aDouble;
float aFloat;
boolean aBoolean;
public static void main(String[] args) {
PrimitiveTypes primitiveTypes = new PrimitiveTypes();
primitiveTypes.printDefaultValues();
}
private void printDefaultValues() {
System.out.println(aByte);
System.out.println(aShort);
System.out.println(anInt);
System.out.println(aLong);
System.out.println(aChar);
System.out.println(aDouble);
System.out.println(aFloat);
System.out.println(aBoolean);
}
}
* 추가로 기본 자료형 중 실수 부분에서 부동소수점 오류가 발생할 수 있는데 이것은 자바언어의 문제가 아니라
컴퓨터는 실수 표현을 부동소수점을 이용하기 때문에 정확한 실수를 저장할 수 없으며, 최대한 완벽에 가깝기를 바라는 근사치를 저장합니다. 그래서 정확한 소수점 계산을 위해 BigDecimal 타입을 사용해야합니다.
System.out.println(0.1-0.01); // 결과 : 0.09000000000000001
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.01");
System.out.println(a.subtract(b)); // 결과 : 0.09
프리미티브 타입과 레퍼런스 타입
프리미티브 타입(기본 자료형), 레퍼런스 타입(참조 자료형)
참조 자료형은 기본 자료형을 제외한 나머지 입니다.
기본 자료형과 참조 자료형이 생성되면 JVM의 Runtime Data Area에 저장됩니다.
그 중에서도 스택 영역과 힙 영역에 저장됩니다.
기본 자료형은 스택 영역에 값이 바로 저장되고, 참조 자료형은 스택 영역에 힙 영역의 주소값을 저장하고 힙 영역에 실제 객체를 생성하여 저장합니다.
기본 자료형과 참조 자료형의 차이는 객체를 생성할 때 new를 사용해서 객체를 생성하는가 이고,
기본 자료형은 +,-,/,* 등 연산자를 이용 할 수 있지만 참조 자료형은 연산자를 이용 할 수 없습니다.
하지만 특별히 참조 자료형인 String 타입은 new 없이도 객체를 생성할 수 있고 + 연산자를 사용할 수 있습니다.
기본 자료형과 참조 자료형의 가장 중요한 차이점은 "Pass by value"와 "Pass by reference"가 있습니다.
기본 자료형을 매개 변수로 사용할 때 "Pass by Value"로 데이터를 전달합니다. 즉 값만 전달합니다. 만약 메소드의 매개 변수로 기본 자료형을 넘기게되면 메소드에서 그 값을 변경하더라도 원래 값은 변하지 않습니다.
참조 자료형은 "Pass by reference"로 값의 주소값을 전달하기 때문에 메소드에서 그 값을 변경하게되면 원래 값도 같이 변하게 됩니다.
리터럴
리터럴은 실제로 저장되는 값 그 자체로 메모리에 저장되어 있는 값 그 자체를 뜻합니다.
예를들면
int num = 1; // 1이 리터럴입니다.
상수와 많은 혼동을 하게되는데 상수는 값을 변할 수 없어서 항상 같은 수를 나타낸 다는 의미이므로 뜻이 서로 다르니 주의하는게 좋습니다.
변수 선언 및 초기화하는 방법
변수를 선언하는 방법은 "타입 변수명;" 으로 선언해줄 수 있습니다.
ex) int num;
변수를 초기화 하는 방법은 "변수명 = 값;" 으로 초기화 할 수 있습니다.
ex) num = 1;
그리고 선언과 초기화를 같이할 수도 있습니다.
int num = 1;
하지만 여기서 주의해야 할 사항은 선언과 초기화를 같이하게 되면 우리 눈엔
int num = 1; 이렇게 한줄로 되어있어서 한번만 동작하는것 처럼 보이지만
실제 소스파일을 오퍼레이션 코드로 보게되면 선언과 초기화를 순서대로 진행합니다.
//@EXP 소스 코드
public class VariableTest {
public static void main(String[] args) {
int num = 1; //선언과 초기화
}
}
//@EXP 오퍼레이션 코드
public class llnote.study.livestudy.VariableTest {
public llnote.study.livestudy.VariableTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_1 //선언
1: istore_1 //초기화
2: return
}
만약 멀티 스레드에서 선언과 초기화를 같이 할경우 데이터가 원치않게 저장될 수 있습니다.
그래서 이 부분은 synchronized 처리를 하거나 주의해서 사용해야합니다.
변수의 스코프와 라이프타임
변수는 크게 4가지가 있습니다.
변수 | 설명 | 스코프 | 라이프타임 |
인스턴스 변수 | 메소드 밖에, 클래스 안에 선언된 변수 | 클래스 내에서 접근 가능 객체를 생성한 후 접근 가능 |
클래스 객체가 생성될 때 변수가 생성되고 참조하는 객체가 없을때 GC에 의해서 소멸 |
클래스변수 | 메소드 밖에, 클래스 안에, static으로 선언된 변수 | 다른 클래스에서 접근 가능 | 프로그램이 시작될때 처음부터 스택에 올라와서 프로그램이 종료될 때까지 살아있음 |
매개 변수 | 메소드의 인자값으로 선언된 변수 | 메소드 내에서만 접근 가능 | 메소드가 시작될때 생성되고 메소드가 종료되면 소멸 |
로컬 변수 | 중괄호 안에서 선언된 변수 | 중괄호 내에서 접근 가능 | 중괄호가 시작될때 생성되고 중괄호가 끝날때 소멸 |
타입변환, 캐스팅 그리고 타입 프로모션
타입은 데이터 타입의 줄임말이고 데이터 타입은 다른말로 자료형이라고도 합니다.
특정 데이터 타입으로 표현된 리터럴은 다른 타입으로 변환 할 수 있는데 이것이 타입변환이고
상황에 따라 타입 캐스팅과, 타입 프로모션으로 나뉘게 됩니다.
타입 캐스팅은 타입을 변환할 시 더 좁은 범위의 타입으로 변환 할때를 말하고 반대로
타입 프로모션은 타입을 변환할 시 더 넓은 범위의 타입으로 변환 할때를 말합니다.
타입 캐스팅의 예를 들면
int a = 100;
short b = a; // 컴파일 에러발생
이런 상황은 int a 가 더 넓은 범위인데 short로 타입을 변경하려고 할 경우 더 좁은 범위로 타입을 변환하기 때문에 캐스팅이 필요합니다.
int a = 100;
short b = (int) a; // (int)가 캐스팅입니다.
대신 억지로 캐스팅을 할 경우 short의 허용 범위를 넘어갈 경우 그 위의 비트는 계산할 수 없습니다.
ex)
int a = 300000;
short b = (short)a;
System.out.println(b+""); // 결과 -27680
반대로 타입 프로모션의 예를 보자면
int a = 100;
long b = a; // 자동으로 타입 프로모션이 일어납니다.
1차 및 2차 배열 선언하기
기본적으로 배열은 레퍼런스 타입 즉 참조 자료형으로 취급됩니다.
그러므로 배열 선언시 스택 영역에 값이 아닌 주소값이 저장됩니다.
배열을 선언하는 방법은 다양합니다.
int intArr11[] = {10};
int intArr12[] = new int[10];
int intArr13[] = new int[]{10};
int intArr21[][] = {{10},{1}};
int intArr22[][] = new int [][]{{10},{1}};
int intArr23[][];
타입추론, var
자바 컴파일러에서 타입을 추론하는것을 Type inference라고 합니다.
자바 10부터 var라는 타입이 추가되었습니다. 로컬 변수를 선언할 때 var를 이용하면 컴파일러가 타입 추론을 할 수 있습니다.
사용조건은 아래와 같습니다.
- 초기화된 로컬 변수 선언 시
- 반복문에서 지역 변수 선언 시
var 활용
var numbers = Arrays.asList(1, 2, 3, 4, 5);
//지역변수 선언 var i = 0;
for (var i = 0; i < numbers.size(); i++) {
System.out.println("numbers = " + numbers.get(i));
}
//forEach
for(var number : numbers){
System.out.println("numbers = " + number);
}
//람다 (java 11부터 지원)
numbers.stream().forEach((var i) -> System.out.println(i));
참고사이트 (catsbi.oopy.io/6541026f-1e19-4117-8fef-aea145e4fc1b)
참고문헌
- 이상민(2017). 자바의 신 2. 서울: 로드북
- 김종민(2015). 스프링 입문을 위한 자바 객체 지향의 원리와 이해. 경기: 위키북스