-
자바 데이터 타입, 변수, 배열JAVA/Java 2020. 12. 26. 20:50
목표
- 자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익히기
프리미티브 타입 종류와 값의 범위 그리고 기본 값
Primitive Type?
- 기본자료형 혹은 원시자료형이라고 불리는 프리미티브 타입은 값을 할당할 때 변수의 주소 값에 값이 그 자체로 저장되는 데이터 타입이다.
- 해당 데이터 타입은 값이 할당되면 앞서 살표 보았던 JVM Runtime Data Area 영역 중 Stack 영역에 값이 저장된다.
종류
- Java에서 프리미티브 타입의 종류는 총 8 가지이다.
- byte, short, int, long, float, double, char, boolean 타입이 그것이다.
- 타입의 종류와 값의 범위 기본값을 다음과 같은 표로 정리해 보았다.
2. 프리미티브 타입과 레퍼런스 타입
Reference Type?
- 참조자료형이라 불리는 레퍼런스 타입의 종류는 무한하다.
- 프리미티브 타입과 달리 JVM Runtime Data Area 영역 중 heap 영역에 할당되는데
- 레퍼런스 타입의 변수 주소 값에는 값이 아닌 heap 영역에 할당된 주소가 저장된다.
- 기본 타입과 참조 타입의 구분은 생각보다 간단하다.
- 저장되는 값이 실제 값인지 혹은 메모리의 주소 값이냐에 따라 구분 가능하다.
1234public static void main(String[] args) {String name = "test";int age = 20;}cs - 레퍼런스 타입의 name과 프리미티브 타입의 age 변수는 런타임 스택 영역에 생성된다.
- 레퍼런스 타입의 값인 주소 값과, 프리미티브 타입의 값 20 역시 런타임 스택 영역에 저장된다.
- 레퍼런스 타입의 값인 주소 값이 가리키는 실제 값은 힙 영역에 객체가 된다.
- 따라서 값을 복사할 때 조심해야 한다.
- 프리미티브 타입의 경우 실제 값이 아닌 주소 값이 복사된다.
- 이러한 복사는 또다시 얕은 복사와 깊은 복사로 나뉘게 되는데
- 얕은 복사는 주소 값을 복사하여 동일한 영역의 객체를 참조하고 깊은 복사는 똑같은 새 객체를 할당한다.
3. 리터럴
literal?
- 리터럴은 변수나 상수에 저장되는 값 그 자체를 의미한다.
int a = 10 - int형에 리터럴은 10이다.
- 고정된 값을 표현하는 리터럴은 정수를 표현하는 리터럴, 실수를 표현하는 리터럴,
- 문자를 표현하는 리터럴, boolean을 표현하는 리터럴, 문자열을 표현하는 리터럴 등이 있다.
정수 리터럴
- 정수를 표현하는 방법은 여러 가지가 있다.
- 일반적으로 사용하는 10진법부터 2진법 8진법 과 같은 방법이 있고
- 자바에서는 다양한 진법을 지원한다. 10진수 26을 다양한 리터럴로 표현해보자.
- Integer Literals
- long 타입은 L로 끝나거나 l로 끝나는 값
- 그 외 나머지 숫자는 int
- 16진수: 0x로 시작
- 2진수: 0b로 시작
int decimal = 26; // 일반적인 형태 10진법
int ocatal = 032; // 제일 앞에 0이 붙으면 8진법
int heaxaDecimal = 0x1a; // 0x가 붙으면 16진법
int binary = 0b11010; // 0b가 붙으면 2진법- 정수 리터럴은 기본적으로 int 형이고, long 타입을 표현하려면 l, L을 마지막에 붙여야 한다.
실수 리터럴
- 실수 타입의 리터럴은 기본적으로 double 타입이고, float 타입으로 표현하려면 f를 명시적으로 붙여야 한다.
Floating-Point Literals
- float 타입은 F로 끝나거나 f로 끝나는 값
- 그 외 나머지는 double (optional, D 혹은 d로 끝나는 값
double a = 0.1;
double b = 1E-1;
float c = 0.1f;문자 리터럴
- 문자는 작은따옴표(') 안에 표현할 수 있다
char a = 'a'; - 또 특수문자를 위한 리터럴들도 있다.
- Character and String Literals
- Unicode character
- special escape character
- \b : 백스페이스
- \t : 탭
- \n : new line
- \f : form feed
- \r : 캐리지 리턴
- \" : 큰따옴표
- \' : 따옴표
- \\ : 역슬래시
문자열 리터럴
- 문자열은 큰따옴표(") 안에 표현할 수 있다.
- 문자열 리터럴에는 조금 특이한 점이 있다.
- 다른 리터럴들은 프리미티브 타입의 값을 표현하기 위해 존재한다.
- 그런데 문자열(String)은 레퍼런스 타입이지, 프리미티브 타입이 아니다.
- 그럼에도 String 타입은 literal을 지원하는데, literal 방식으로 String에 값을 주면 Heap 영역에서 String constant pool이라는 특수한 영역에 값이 저장된다.
- 그리고, 동일한 값을 쓰는 경우에 다른 일반적인 레퍼런스 타입처럼 Heap에 또 올라가지 않고, String constant pool에 존재하는 값을 참조하는 방식으로 작동한다.
해당 관련 링크 : String Constant Pool
boolean 리터럴
- true, false로 표현할 수 있다.
boolean a = false;
boolean b = true;4. 변수 선언 및 초기화하는 방법
Declaration?
- 변수를 선언한다는 것은, 저장공간을 확보하겠다는 의미로 해석할 수 있다.
int a; - 위의 코드가 변수를 선언한 것인데, 해석하자면 다음과 같다.
- int 타입의 값을 저장할 수 있는 공간을 확보했고(int 타입은 4byte) 그 공간을 지칭할 이름은 a이다.
Initialization?
- 변수를 초기화한다는 것은, 저장공간에 원하는 값을 저장하는 것을 의미한다.
- 변수를 선언하고 나면, 해당 공간에는 아무런 의미 없는 쓰레기 값이 들어가 있게 된다.
- 그리고 그 상태에서 컴파일을 시도하면
- Error:(10, 28) java: variable a might not have been initialized와 같은 컴파일 에러코드를 볼 수 있을 것이다.
- 그러므로 변수는 선언 후에 초기화를 해야 하며 위에 선언한 변수에 대한 초기화는 다음과 같이 할 수 있다
a = 10; // 선언 후 초기화 - 변수의 선언과 초기화를 한 줄에 하는 것도 가능하다.
int a = 10; // 선언 과 초기화 5. 변수의 스코프와 라이프타임
Scope? LifeTime?
- 변수의 스코프란 해당 변수를 사용할 수 있는 영역 범위를 뜻하고
- 라이프타임은 해당 변수가 메모리에 언제까지 살아있는지를 의미한다.
- 변수의 경우 scope에 따라 Instance Variables, Class Variables, Local Variables로 나눌 수 있다.
Instance Variables
- 클래스 안에서 선언되어있고, 어떠한 method나 block안에서 선언되지 않은 변수
- scope - static method를 제외한 클래스 전체
- lifetime - 클래스를 인스턴스 화한 객체가 메모리에서 사라질 때까지
Class Variables
- 클래스 안에서 선언되어있고, 어떠한 메서드나 블록 안에서 선언되지 않았으며 static 키워드가 포함되어 선언된 변수
- scope - 클래스 전체
- lifetime - 프로그램 종료 시까지
Local Variables
- 인스턴스 변수, 클래스 변수가 아닌 모든 변수
- scope - 변수가 선언된 block 내부
- lifetime - control 이 변수가 선언된 block 내부에 있는 동안
6. 타입 변환, 캐스팅 그리고 타입 프로모션
Type casting?
- 타입 캐스팅이란 크기가 더 큰 자료형을 크기가 더 작은 자료형에 대입하는 것을 의미한다.
- 예를 들어 int(4byte) 타입의 데이터를 byte(1byte) 타입에 대입하는 경우가 있을 수 있겠다.
- 물론, 데이터 크기가 더 크기 때문에 변환 과정에서 데이터의 손실이나 변형이 올 수도 있다.
Type promotion?
- 타입 캐스팅과 반대로 크기가 더 작은 자료형을 더 큰 자료형에 대입하는 것을 의미한다.
- 예를 들어 byte(1byte) 타입의 데이터를 int(4byte) 타입에 대입하는 경우이다.
- 그리고 이 경우에는 데이터 손실이나, 변형이 오지 않음으로 캐스팅할 때처럼 명시적으로 적지 않아도 자동으로 변환이 가능하다.
- 위와 같은 타입 변환은 프리미티브 타입뿐만 아니라 레퍼런스 타입에서도 가능하다.
- 그런데 레퍼런스 타입에도 크기라는 개념으로 캐스팅과 프로모션을 구분 지어 생각하면 헷갈릴 수 있다.
- 부모 클래스로의 타입 변환은 자동적으로 가능하지만 자식클래스로의 타입변환은 타입 캐스팅이 필요하다.
- 조금만 생각해보면 당연한 이유인데, 자식 클래스는 부모 클래스의 필드나 메서드를 물려받음으로 자식 클래스 타입의 객체를 부모 클래스 타입으로 바꾼다고 해서 데이터의 손실이나 변형이 일어나진 않기 때문이다
7. 1차 및 2차 배열 선언하기
1차원 배열
- oneDimensionArrayEx1 은 Runtime Stack 영역의 힙 영역 주소 값을 가진다.
- Heap 영역에 int 타입 크기의 요소 5개를 할당하여 사용된다.
2차원 배열
- Runtime Stack 영역의 twoDimensionArrayEx1 은 2개의 요소 크기(2개 요소에 주소값을 가지고 있음)를 가진 힙 영역 주소값을 가진다.
- 힙 영역에는 실제 값이 들어있는 요소들과 주소 값이 들어있는 요소들로 존재하게 된다.
8. 타입 추론, var
-
10 버전 이상부터 type inference 기능이 추가되었다.
-
method 호출 및 선언과 variable 혹은 object 선언을 통해 실제 타입을 추론하는 형식
-
Generic type
- C++의 template과 비슷한 개념으로 보인다.
- 그러나 Generic 은 primitive type 사용 불가하다.
- template 과는 다르게 type-erasure 개념이 적용되어 type safe를 최대한 보장하려고 노력한다.
-
type-erasure: 컴파일러가 parameterized type에서는 새로운 클래스들이 생성되지 않는 걸 보장한다.
-
컴파일러가 unbound type T를 Object로 변환한다.
-
결국 생성된 바이트코드에는 원래의 class, interface, method 만을 포함하고 있다.
-
-
-
var라는 type keyword를 사용하여 실제 타입을 추론
- var 라는 type keyword 를 사용하여 실제 타입을 추론
'JAVA > Java' 카테고리의 다른 글
JAVA 연산자 (0) 2020.11.29 Maven에 대해서 알아보자 (0) 2020.08.30 서블릿 Life Cycle 알아보기 (0) 2020.06.02 왜 Wrapper 클래스는 쓰이는 걸까? (1) 2020.05.21 객체의 해시코드(hashCode())란 (0) 2020.05.19