값을 할당할 때 변수의 주소값에 값이 그 자체로 저장되는 데이터 타입이다. 해당 데이터 타입은 값이 할당되면 JVM Runtime Data Area 영역 중 Stack 영역에 값이 저장된다.
Java 에서 프리미티브 타입의 종류는 총 8 가지 이다.
프리미티브 타입은 결정적으로 스택 메모리에 저장이 된다.
그리고 초기화 할때 0으로 자동으로 초기화된다.
참조자료형 이라 불리는 레퍼런스 타입의 종류는 무한하다. 프리미티브 타입과 달리 JVM Runtime Data Area 영역 중 heap 영역에 할당되는데 레퍼런스 타입의 변수 주소값에는 값이 아닌 heap 영역에 할당된 주소가 저장된다.
레퍼런스 타입의 값인 주소값이 가리키는 실제 값은 가비지 컬렉션 힙 영역에 객체가 생성 된다.
이때 값 복사에 대해 주의해야하는데 복사시 값이 아닌 주소값이 복사되기 때문이다. 이를 주소에 의한 복사 (call by reference) 라고 한다.
리터럴은 변수나 상수에 저장되는 값 그 자체를 의미한다. 그 종류로는 정수, 실수, 문자, 논리, 문자열 등이 있다.
정수를 표현하는 방법은 여러가지가 있다. 일반적으로 사용하는 10진법 부터 2진법 8진법 과 같은 방법이 있고 자바에서는 다양한 진법을 지원한다.
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를 명시적으로 붙여야한다.
double a = 0.1; // 0.1
double b = 1E-1; // 0.1
float c = 0.1f; // 0.1
문자는 작은따옴표(')안에 표현할 수 있다
char a = 'H';
char b = "한";
char c = \uae00;(유니코드값)
(\u다음에 4자리 16진수로, 2바이트의 유니코드(Unicode))
true, false 로 표현할 수 있다.
boolean a = true;
boolean b = false;
문자열은 큰따옴표(")안에 표현할 수 있다.
String a = "abc"; // abc
문자열(String)은 레퍼런스 타입이지, 프리미티브 타입이 아니다.
그럼에도 String 타입은 literal 을 지원하는데, literal 방식으로 String 에 값을 주면 Heap 영역에서 String constant pool 이라는 특수한 영역에 값이 저장된다. 그리고, 동일한 값을 쓰는 경우에 다른 일반적인 레퍼런스타입 처럼 Heap 에 또 올라가지 않고, String constant pool 에 존재하는 값을 참조하는 방식으로 작동한다.
변수의 스코프란 해당 변수를 사용할 수 있는 영역범위를 뜻하고 라이프타임은 해당 변수가 메모리에 언제까지 살아있는지를 의미한다.
변수의 경우 scope 에 따라 Class Variables
, Instance Variables
, Local Variables
로 나눌 수 있다.
ex)
class A {
int instanceValue; //Instance Variables
static int classValue;//Class Variables
void method(){
int localValue = 0; //Local Variables
}
}
자바에서는 배열을 만들기 위해서는 new키워드를 사용합니다. new를 보면 알 수 있듯, Heap 영역에 저장된다.
ex)
int[] oneDimensionArrayEx1 = {1, 2, 3, 4, 5};
int[][] twoDimensionArrayEx1 = {{1, 2}, {3, 4}};
자바 컴파일러에서 타입을 추론하는 것을 Type Inference
이라 한다.
static <T> T pick(T a1, T a2) { return a2; }
public static void main(String[] args) {
Serializable d = pick("d", new ArrayList<String());
}
위 코드를 보면 pick 메소드의 매개변수는 T이고 메소드의 매개변수 a1, a2 둘 다 T 타입이다.
하지만 pick 메소드를 호출하면서 첫 번째 인자로 String을 주고 두 번째 인자로 ArrayList를 주는데 이런 경우 모든 인자에 어울리는 선(공통 부모)란 Serializable으로 String과 ArrayList 둘 다 Serializable
을 구현하고 있기 때문이다.
String
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
모두 공통 부모인 Serializable
를 구현하고 있다.
Java 컴파일러가 컨텍스트로부터 타입추론이 가능하다면 Generic 클래스의 생성자를 호출하기 위해 필요한 type arguments를 비어있는 type witness(<>, the diamond)로 대체할 수 있다.
List<String> myList1 = new ArrayList<String>(); // Case 1
List<String> myList2 = new ArrayList<>(); // Case 2
Java SE 7
이후로 컴파일러는 the diamond(<>)를 사용하는 경우 generic 클래스의 실제 type argument까지 추론가능하다.자바의 경우 Java 10에서부터 var라는 Local Variable Type-Inference 가 추가되어 사용되고 있다.
var 키워드는 지역변수이면서 선언과 동시에 초기화가 필수적으로 요구된다.
ex)
var message = "ABCD";
자료형 없이 단순하게 var라는 지역변수로 선언했음에도 컴파일러는 오른쪽에 있는 초기화 값을 통해 해당 변수의 타입을 유추한다. 하지만 이런 var 역시도 다이아몬드 연산자 방식은 지원하지 않는다.
즉, 아래와 같은 타입은 지원하지 않는다.
//아래 소스는 타입을 유추할 수 없기 때문에 컴파일 에러가 발생한다.
var messages = new ArrayList<>();
참조