Wanna be Brilliant Full-Stack Developer

2/16 Java 일반변수와 레퍼런스 변수 의 차이? 본문

Some Memos/Java

2/16 Java 일반변수와 레퍼런스 변수 의 차이?

Flashpacker 2022. 2. 16. 21:43

목표 : 레퍼런스 변수와 일반변수의 차이가 무엇인지 알아보자!

package ch02;

// new가 되어서 힙에 할당이 될 떄 사이즈를 알 수 있다. ( 프로그램이 실행되었을 떄 = Runtime)
class MyData {
	int id = 1;	//4Byte
	int price = 1000;	//4Byte
}

// 레퍼런스(참조) 변수, 일반 변수
public class VarRefEx01 {
	
	public static void main(String[] args) {
		int num = 10; // 일반변수 (크기가 정해져 있는 것) 
		MyData d; // 레퍼런스 변수 (크기가 정해져 있지 않는것) 
	}
}

int와 같이 크기가 정해져 있는 것을 일반 변수라고 한다! 

어떤것을 일반 변수라고 안하냐면 

위에 Mydata라는 것은 원래 없는 타입인데 내가 만든 타입이다. Mydata라는 타입에는 int id와 int price가 있는데 각각 4바이트씩 MYdata는 8 바이트군아 라는걸 우리 입장에서 알 수 있지만 

자바 입장에서는 Mydata라는 타입은 없었기 떄문에 new가 되어서 Heap에 할당이 될 떄 사이즈를 알 수 있다.

 

new가 될때 heap에 할당 되어 사이즈를 알 수 있다는 의미는 무엇이 냐면 프로그램이 실행되었다는것이다. 프로그램이 실행되었을 떄 이거를 프로그램에서는 Runtime이라고 한다 ! 실행이 되었을떄 Mydata가 8바이트인지 알 수 있다. 

 

MyData는 내가 만든 타입이기 떄문에 자바 입장에서 사이즈를 알수없다.

MyData d;

이런 변수를 레퍼런스 변수라고 한다 . 크기가 정해져있다는것은 = 컴파일 시점을 말한다! 실행하기 전부터 사이즈를 알수 있어야하는데 MyData타입의 d 사이즈가 8바이트인지는 실행하기전에는 알수 없다! 

package ch02;

// new가 되어서 힙에 할당이 될 떄 사이즈를 알 수 있다. ( 프로그램이 실행되었을 떄 = Runtime)
class MyData {
	int id = 1;	//4Byte
	int price = 1000;	//4Byte
}

// 레퍼런스(참조) 변수, 일반 변수
public class VarRefEx01 {
	
	public static void main(String[] args) {
		//타입 변수; int num; 변수를 선언한다.
		// 타입 변수 = 값; int num = 10; 변수를 초기화한다! 
		int num; // 일반변수 (크기가 정해져 있는 것) 
		MyData d = new MyData(); // 레퍼런스 변수 (크기가 정해져 있지 않는것) 
	}
}

int num; 이라고 적혀있으면 변수를 선언한다

int num = 10; 변수를 초기화한다 라고 말하는데 여기서 초기화 한다는것은 메모리에 할당한다는 말이다

int num;        MyData d; 둘다 아직 메모리에 할당 되지 않았다.

int num;은 메모리에 할당하기전에 몇바이트를 할당해야 할지 컴파일시에 JVM은 알수있나? 알수있다. 왜냐하면 int는 4바이트니까 컴파일 시점에서 알수 있는데 

MyData는 알수 없다. MyData는 무슨 타입일까 컴파일 시에는 알수 없다. 

 


우리가 창고를 가지고 있다. 이 창고가 어떻게 만들어져 있냐면 총 12 칸의 칸을 가지고 있다. 

내가 창고를 설계할때 하나가 1바이트라고 하면 int num = 10; 이라는 글자를 봤으면 보자마자 num값을 저장하는 군아 미리 알 수 있다. 이게 int 타입이니까 창고를 어떻게 설계해야할지 알수 있고 창고에 재는 이정도 필요하군아 해서 미리 창고 공간(4칸) 을 확보해놓을 수 있다. 

 

만약 MyData d = new MyData(); 이건 내가 한번도 보지 못한 데이터 타입이라서 이거를 얼마나 설계를 해놔야하는지 애가 몇칸을 차지할까  , 만약 20칸을 차지할까? 20칸을 차지하면 창고가 모자른데 이런 생각을 할 수 있다.

이러한 커스텀 타입(개발자가 만든 타입)은 이런 글자를 보고 JVM이 이해하는 .Class 파일로 컴파일 할때 크기를 알 수가 없다. 

알수 없는데 언제 알수 있냐면 .Class를 JVM에 얹어서 실행할떄 new Mydata(); 런타임 되는 순간 MyData로 가보니까 int와 int 두개 8바이트라는것을 알수 있다. 

 

자바를 만든 사람 입장에서 보기에는 애들이 8바이트 100 바이트 ,1000바이트 10000바이트 알수가 없고 동적이다.

int num = 10 ; 과 같은 애들은 정적이다. 프로그램 시작하기 전부터 알수가 있다. 자바에서 정해진 기본 자료형들이라 알수 있지만 커스텀 타입은 실행하기 전까지는 크기는 알 수없고 창고를 얼마나 만들어야할지 알수 없다. 

 

저 12칸 창고는 강남에 있어서 비싸지만 애들은 어떻게 하냐면 시골 변두리 쪽에 싼가격에 엄청 큰 땅에 큰 창고를 만들어 놓고 이 공간을 머라고 부르냐면 heap공간이라고 부른다.

쌀을 저장해 놓는 곳간이라 생각해보자!

MyData d = new MyData();를 보고 실행하기전에는 크기를 알 수 없기떄문에 얼마를 확보 해놓으냐면 

무조건 4바이트를 할당해놓는다. 

그러면 4바이트는 데이터를 저장하는것이 아니라 

저 heap 공간에 1번지부터 3천번지까지 있다고하면 저 강남 창고에 2000번지를 저장 해놓는거다? 

커스텀 타입의 사이즈는 항상 4바이트다 , 2000번지는 주소이다, 누구를 찾는 주소냐면 밑에 heap공간에 2000번지를 찾는 주소이다.  

그래서 MyData의 d는 어디를 가리키고있냐면 4바이트( 2000번지의 주소)를 가지고있는곳을 가리키고 

왔더니 값이 있는것이 아니라 주소를 가지고 있다.  이주소를 보고 2000번지군아 해서 밑으로 내려간다 이렇게 두번 움직인다! 

int num은 바로 저장해있는곳으로 가면 값 10이 있는거다. 

일반 변수와 레퍼런스 변수의 차이는 심플하다

일반 변수는 값을 가지고 있고 레퍼런스 변수는 주소를 가지고 있다.

 

일반 변수는 그 공간의 값을 가지고 있고 레퍼런스 변수는 그 공간의 주소를 가지고 있다. 

이유는 무엇인가? 

일반 변수는 컴파일시 크기를 알수 있고 , 레퍼런스 변수는 실행하기 전에는 크기를 알수 없다. 

크기를 알수 없으니까 창고 설계가 불가능하니까 엄청나게큰 공터를 만들어놓고 그 공터에 공간이 많으니까 공간을 활용하는것이다. 창고에는 주소를 저장해놓고 이 주소를 통해서 heap공간에 가서 실제 데이터를 찾아가는것이다. 

실제 2000번지에는 int id = 1 4공간하고 int price =1000 에 4공간 이런식으로 저장이된다.

 

다시또 정의 하자면 레퍼런스 변수는 주소를 가지고 있고 일반 변수는 값을 가지고 있다. 

레퍼런스 변수는 값을 2번만에 찾아낸다 

일반변수는 한번에 찾는다. 

레퍼런스 변수의 주소를 가지고 있는 이거를 C언어에서는 포인터라고 부른다

이 포인터를 통해서 값을 찾아내는것이다. 포인터라는 개념은 단순하다 

내가 크기를 알 수 없으니까 메모리 공간 설계가 불가능하고 다른 엄청나게 넓은 공간을 임대해놓고 그공간에 데이터를 저장하고 실제 내가 자주쓰는 창고에는 주소를 저장해놓는 것이다. 

 

이게 일반 변수와 레퍼런스 변수의 차이이다. 일반 변수는 자바에서는 기본 자료형! 8가지가 있다 우리가 배운건 Int , double , boolean, char 가 있다. 이런거는 미리 크기를 알수있다. 

레퍼런스 변수는 자바에는 어떤것들이 있냐면 내가 만든 class 자료형 (Bean)같은거 레퍼런스 변수이다 

왜 미리 크기를 알 수 없기 떄문에! 

package ch02;

// new가 되어서 힙에 할당이 될 떄 사이즈를 알 수 있다. ( 프로그램이 실행되었을 떄 = Runtime)
class MyData {
	int id = 1;	//4Byte
	int price = 1000;	//4Byte
}

// 레퍼런스(참조) 변수, 일반 변수
public class VarRefEx01 {
	
	public static void main(String[] args) {
		//타입 변수; int num; 변수를 선언한다.
		// 타입 변수 = 값; int num = 10; 변수를 초기화한다! 
		int num = 10;// 일반변수 (크기가 정해져 있는 것) 
		MyData d = new MyData(); // 레퍼런스 변수 (크기가 정해져 있지 않는것) 
		
		System.out.println(num);
		System.out.println(d.id);
		System.out.println(d.price);
		
	}
}

num은 10, d.id 는 1, d.price는 1000