[Java] static 변수 이해 과정에서 필요 - 전역변수&지역변수, 메모리 구조와
1-1 전역변수와 지역변수
자바에서 변수는 선언의 위치에 따라 전역변수와 지역변수로 나뉘게 된다.
전역변수는 의미 그대로, 어디서든 호출하면 사용할 수 있는 변수이다.
예제)
class Example01{
int Global_int; // 전역변수(객체변수) Example01 이라는 클래스 생성 시 메모리에 저장되어, 계속해서 불러올 수 있는 변수
static int Global_st_int; // 전역변수(클래스변수) 메모리에 저장되어, 본 클래스 뿐만 아니라 다른 클래스에서도 호출이 가능
void addMethod(int a, int b, int c){
// a,b,c 는 모두 지역변수. {} 안에서만 사용되며, addMethod가 종료되면 메모리에서도 삭제됨
Global_int = a + b;
}
}
addMethod를 실행하면
우선 a, b, c라는 지역변수가 생성되고, 그 중 a와 b는 더해져서 Global_int 라는 전역변수값으로 대체되어 저장된다.
그 후 a, b, c라는 지역변수는 addMethod가 종료됨과 동시에 메모리에서 삭제되고,
a+b라는 값을 가진 Global_int 라는 전역변수, 그리고 값이 주어지지 않은 Global_st_int 라는 클래스 변수가 저장된다.
1-2 전역변수의 종류 ( 객체변수와 클래스변수 )
1. 객체변수란, 인스턴스 변수를 의미한다. 즉 하나의 개체값이라고 볼 수 있다. 따라서 new 라는 메소드를 사용하여 매번 새로운 객체변수를 생성 후, 입력 value, 인스턴스 값을 입력하여야만 한다.
2. 클래스 변수란 static 변수, 정적변수를 의미한다. 클래스 변수의 가장 큰 특징은 하나의 저장 공간, 메모리 공간을 차지한다는 점이다. 즉 해쉬코드가 변하지 않은 채, 내부의 데이터값을 공유시킬 수 있고, 하나의 클래스 변수 데이터를 변화시켜줌으로써 전체 클래스 변수를 참조하는 데이터의 값들을 일괄적으로 변화줄 수 있다.
class Card {
String Kind;
int Number;
static int width = 200;
static int height = 300;
}
public class Example02 {
public static void main(String[] args){
// static 변수, 클래스 변수 출력에는 객체 선언이 불필요.
System.out.println("Card의 너비는 "+Card.width+"mm 이다.") // Card의 너비는 200mm이다.
System.out.println("Card의 높이는 "+Card.height+"mm 이다.") // Card의 높이는 300mm이다.
// 객체변수, 인스턴스 변수 출력
Card c1 = new Card(); // Card() 라는 새로운 객체를 new, 즉 새로 생성해야 함.
c1.kind = "Heart";
c1.Number = 8;
Card c2 = new Card();
c2.Kind = "space";
c2.Number = 2;
c1.width = 250;
c1.height = 350;
System.out.println("Card1의 종류는 " + c1.kind + "이고, 숫자는 " + c1.Number + "이다.");
System.out.println("Card2의 종류는 " + c2.kind + "이고, 숫자는 " + c2.Number + "이다.");
System.out.println("Card의 너비는 "+Card.width+"mm 이다.")
System.out.println("Card의 높이는 "+Card.height+"mm 이다.")
}
출력결과
1) Card의 너비는 200mm이다.
2) Card의 높이는 300mm이다.
3) Card1의 종류는 Heart이고, 숫자는 8이다.
4) Card2의 종류는 space이고, 숫자는 2이다.
5) Card의 너비는 250mm이다.
6) Card의 높이는 350mm이다.
와 같이 출력된다.
2. 메모리구조 ( static, stack, heap )
2-1 static area ( 스태틱 메모리 영역 )
하나의 자바 파일은 필드, 생성자, 메소드로 구성된다. 그 중 필드 부분에서 선언된 전역변수와 정적 멤버변수(static이 붙은 자료형 변수) 는 static area에 데이터를 저장한다. 그리고 이곳에 저장된 데이터는 프로그램의 시작부터 종료까지 메모리에 남아있게 되며, 따라서 전역변수는 프로그램 가동 중에는 어디서든 사용이 가능해진다.
따라서 전역변수나 static 변수를 무분별하게 사용하면 메모리 용량을 많이 차지하게 된다.
2-2 stack area ( 스택 메모리 영역 )
메소드 내에서 사용하는 지역변수( int, long, boolean, double.... 등 ) 의 데이터 값이 저장되는 공간이다. 따라서 해당 메소드의 사용이 종료되면 메모리가 해제된다.
public class StackAreaEx {
public static void main(String[] args) {
int a = 5; a = 4; a = 3; a = 2;
System.out.println(a);
for(int i=0; i<5; i++){
}
// System.out.println(i); 컴파일 에러
}
}
위의 소스 코드처럼 a라는 변수는 main 메소드가 호출될 때 Stack 영역에 할당되고 종료 시 해제된다.
또한 a라는 변수의 값이 5, 4, 3, 2 순으로 값을 할당하였고 출력되는 값은 2가 출력된다. 이전 데이터는 지워지는 것이고 2라는 값만 출력된다.
즉, Stack 영역은 LIFO(Last In First Out)의 구조를 갖고 변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다는 것을 알 수 있다.
* LIFO = 가장 마지막에 들어온, 쓰여진, 입력된 데이터값이 가장 먼저 출력되는 것.
또한 for문 내에 int i를 정의하였는데 for문이 종료된 다음 i를 출력하지 못하는 이유는 지역변수이므로 for문의 종료와 함께 Stack 영역에서 해제되었기 때문이다.
=> 무슨 의미냐면 i 라는 지역변수가 정의된 것은 for문을 통한 {} 중괄호 안에서였기 때문에, for문이 닫힌 뒤의 i라는 값을 출력하려고 해도 i 라는 변수는 이미 메모리에서 지워져서 오류가 난다.
2-3 heap area ( 힙 메모리 영역)
인스턴스를 생성하는 방법은 "클래스 변수 = new 클래스();" 라는 것을 기억하면서 밑에 내용을 확인해 보자.
* 참조값, 해쉬코드 = 가상머신에서 자동적으로 생성되는, 객체를 구분하기 위한 유일한 기본key 값.
참조형(Reference Type)의 데이터 타입을 갖는 객체(인스턴스), 배열 등은 Heap 영역에 데이터가 저장된다. 이때 변수(객체, 객체변수, 참조변수)는 Stack 영역의 공간에서 실제 데이터가 저장된 Heap 영역의 참조값(reference value, 해시코드 / 메모리에 저장된 주소를 연결해주는 값)을 new 연산자를 통해 리턴 받는다. 다시 말하면 실제 데이터를 갖고 있는 Heap 영역의 참조 값을 Stack 영역의 객체가 갖고 있다. 이렇게 리턴 받은 참조 값을 갖고 있는 객체를 통해서만 해당 인스턴스를 핸들 할 수 있다.
public class HeapEx01 {
public static void main(String[] args) {
int[] a = null; // int형 배열 선언 및 Stack 영역 공간 할당
System.out.println(a); // 결과 : null
a = new int[5]; // Heap 영역에 5개의 연속된 공간 할당 및
// 변수 a에 참조값 할당
System.out.println(a); // 결과 : @15db9742 (참조값) 가상머신에서 부여하는 임의의 기본키
}
}
public class HeapEx02 {
public static void main(String[] args) {
String str1 = new String("joker");
String str2 = new String("joker");
if(str1 == str2){
System.out.println("같은 주소값 입니다.");
}else{
System.out.println("다른 주소값 입니다."); // str1과 str2는 다른 참조키를 가지고 있기 때문에 다른 주소값이 나온다.
}
}
}
참고자료 :
https://java119.tistory.com/20
https://m.blog.naver.com/heartflow89/220954420688
https://kephilab.tistory.com/46