Primitive Type(원시 타입)과 Reference Type(참조 타입)
Primitive Type(원시 타입)
자바에 내장되어 있는 기본형(원시) 타입으로써 미리 정의된 정수, 실수, 논리, 문자형의 타입을 제공한다.
Reference Type(참조 타입)
앞서 설명한 원시 타입을 제외한 모든 타입을 참조 타입이라고 한다. (배열, 열거, 클래스, 인터페이스 타입이 여기에 속한다.)
Primitive Type 종류와 값의 범위 그리고 기본 값
literal(리터럴)
소스 코드의 고정된 값을 의미 한다. 그렇다면 Constant(상수) 와 같은 의미 일까? 아니다. 상수는 값 자체(리터럴)를 담기위해 메모리에 할당된 공간이다. 예를 들어보자.
final int test = 5;
test라는 상수(공간)에 5라는 정수 리터럴(값 그자체)을 담았다.
리터럴은 상수와 똑같이 값이 변하지 않도록 저장되지만 공간과 값 그자체 라는 차이에서 엄연히 다르다. (상수는 test라는 이름을 가지고 있고 리터럴은 값 그자체이기 때문에 이름이 없다)
변수 선언 및 초기화하는 방법
변수를 선언 및 초기화 하는 방법에는 3가지가 있다.
명시적 초기화(explicit initialization)
가장 많이 사용하고 기본적인 방식으로써 선언과 동시에 초기화를 한다.
public class Test{
int test = 5;
}
멤버 변수의 경우 초기화를 하지 않고 선언만 할 시 타입에 해당하는 기본 값으로 초기화가 이루어진다. 그러나 지역 변수의 경우 초기화를 하지 않으면 컴파일 에러가 발생한다.
(컴파일러에 의해 멤버 변수는 체크가 가능하나, 지역 변수는 체크하지 않는다.)
public class Test{
int test; // 정상 (컴파일 단계에서 컴파일러가 체크하여 타입에 맞는 기본값으로 부여함.)
int test1 = test; // 정상
public void local(){
int a; // 초기화 되지않음.
int b = a; // 컴파일 에러 발생 (초기화 되지 않은 변수를 부여하려 했기 때문.)
}
}
되도록 선언과 동시에 초기화를 하는것이 바람직하다.
생성자(constructor)
new 키워드를 사용, 생성자를 이용하여 초기화 하는 방법이다. 생성자는 클래스의 인스턴스 변수 초기화 메서드로써 인스턴스 변수를 초기화 할때 혹은 인스턴스 생성 후 실행할 작업을 위해서 사용된다. 생성자를 사용하기 위해선 클래스 내에 클래스와 동일한 이름의 메서드를 생성해야 한다. (매개변수의 타입이나 갯수를 다르게 하여 오버로딩을 활용한 초기화가 가능하다.)
public class TestMain {
String a = "";
public TestMain(){
this.a = "기본 생성자";
}
public TestMain(String a){
this.a = a;
}
public static void main(String[] args) {
TestMain tm = new TestMain("생성자를 통한 초기화"); // 매개변수를 갖는 생성자 호출
System.out.println(tm.a); // a = "생성자를 통한 초기화"
}
}
초기화 블록(initialized block)
클래스 필드의 복잡한 초기화를 담당하는 블록을 의미하며 중괄호 { } 안에 구문을 작성한다. 초기화 블록은 인스턴스 초기화 블록, 클래스 초기화 블록으로 구분 된다. 각 블록 별로 실행되는 시점이 다르며, 인스턴스/클래스 별 공통 선행 작업에 대한 코드 중복을 최소화 할 수 있다.
인스턴스 초기화 블록(instance initialized block)
클래스 인스턴스가 생성 될 때마다 수행된다. 생성자 호출 이전에 수행 되므로 각각의 생성자를 통해 인스턴스를 초기화 할때 마다 수행되어야 할 선행 작업이 있다면 코드 중복을 최소화 할 수 있다.
클래스 초기화 블록(class initialized block)
스태틱 초기화 블록 이라고도 부르며 클래스가 로딩 될때 딱 한번 실행된다. (각 클래스당 최초 1회) 인스턴스 초기화 블록 호출 이전에 수행 되므로 클래스 로딩 시에 수행되어야 할 공통 선행 작업을 실행할 때 유용하다. 클래스 초기화 블록은 중괄호 앞에 static을 붙인다.
public class TestMain {
String a = "";
public TestMain(){
this.a = "기본 생성자";
System.out.println("기본 생성자 호출");
}
public TestMain(String a){
this.a = "매개변수 생성자";
System.out.println("매개변수 생성자 호출");
}
{
System.out.println("인스턴스 생성");
}
static {
System.out.println("클래스 로딩");
}
public static void main(String[] args) {
TestMain tm2 = new TestMain();
TestMain tm1 = new TestMain("생성자를 통한 초기화");
// 결과
// 클래스 로딩
// 인스턴스 생성
// 기본 생성자 호출
// 인스턴스 생성
// 매개변수 생성자 호출
}
}
변수의 Scope와 Lifetime
자바에서는 영역에 따른 변수의 종류 마다 사용할 수 있는 범위(Scope)와 생명시간(Lifetime)이 각각 존재한다.
변수 종류(Variable Type) | 범위(Scope) | 생명시간(Lifetime) |
---|---|---|
인스턴스 변수 (Instance Variable) | 클래스 내 모든 영역 (static 영역의 경우 인스턴스를 생성해야한다.) | 객체 생성 이후 ~ 메모리내에서 제거되는 시점 |
클래스 변수 (Class Variable) | 클래스 내 모든 영역 | 클래스 초기화 이후 ~ 프로그램 종료 시점 |
지역 변수 (Local Variable) | 해당 변수가 선언된 블록 내 모든 영역 | 변수 선언 이후 ~ 블록을 벗어나는 시점 |
public class Test {
String instanceVar = "instanceVar"; // 인스턴스 변수, 멤버 변수라고도 불리며 클래스 내 모든 영역에서 사용 가능 하다. 그러나 static 영역의 경우, 인스턴스를 생성해야 사용 가능하다. (Instance Variable)
static String classVar = "classVar"; // 클래스 변수, 클래스 내에서 공유되며 어떤 곳이든 사용 가능하다. (Class Variable)
public void testMethod() {
String localVar = "localVar"; // 지역 변수, Method 영역(블록)에 선언한 변수(Local Variable)
System.out.println(classVar); // 가능
System.out.println(instanceVar); // 가능
System.out.println(localVar); // 가능
}
public static void main(String[] args) {
// static 영역의 경우 인스턴스 변수 사용 시, 인스턴스를 생성하여 사용해야한다.
System.out.println(classVar); // 가능
System.out.println(localVar); // 에러 발생, 변수가 선언 된 영역을 벗어남.
Test test = new Test();
System.out.println(test.instanceVar); // 가능
}
형변환
형변환 은 어떠한 변수 혹은 상수의 타입을 다른 타입으로 바꾸는 것을 의미하며 프로그램 실행 도중 자동으로 형변환 되는 경우인 묵시적 형변환(Type Promotion), 형 변환될 타입을 직접 명시하는 경우인 명시적 형변환(Type Casting)으로 구분 된다.
묵시적 형변환(Type Promotion)
자동 형변환 이라고도 부르며 프로그램 실행 도중 type 별 byte 크기에 따라 작은 크기의 type이 큰 크기의 type으로 저장 될 때 자동적으로 형변환이 일어난다.
byte(1) < short/char(2) < int(4) < long(8) < float(4) < double(8)
float이 4byte 임에도 long 보다 큰 이유는 표현할 수 있는 값의 범위가 long보다 더 크기 때문이다.
byte byteVar = 2;
short shortVar = byteVar // 묵시적 형변환 발생
그러나 char 타입(표현 범위 0~65535)은 음수를 표현할 수 없기 때문에 음수를 표현할 수 있는 byte 타입에서 char 타입으로의 묵시적 형변환은 일어나지 않는다. (명시적 형변환의 경우는 가능)
byte byteVar = -2;
char charVar = byteVar // 컴파일 에러 발생
명시적 형변환(Type Casting)
강제 형변환 이라고도 부르며 Casting 연산자 ()를 사용해 타입을 직접적으로 명시함에 따라 큰 크기의 type을 작은 크기의 type으로 강제 변환 할 수 있다. 그러나 값의 범위가 변환 하려는 값의 범위를 초과 하는 경우 값 손실이 일어나며 원래 값이 보존되지 않는다.
int intVar = 2;
byte byteVar = (byte)intVar; // 명시적 형변환, 원래 값 보존, 2를 return
int intVar2 = 999999;
byte byteVar2 = (byte)intvar; // 명시적 형변환, 원래 값을 보존하지 못함, 63을 return
두번째 코드의 경우, int(4byte)의 byte(1byte) 값 만큼만 잘라서 저장한다.
999999 = 00001111 01000010 00111111 (63을 저장)
값 뿐만 아니라 객체 참조변수도 형변환이 가능하다. (나중에 따로 다룰 예정)
타입 추론, var