본문 바로가기
Java/Java

변수) 전역변수(인스턴스 변수, static 변수), 지역변수

by 박채니 2022. 3. 16.
SMALL

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


변수는 크게 두가지로 나뉘고, 그 중 전역 변수에서도 두 가지로 나뉩니다.

 

▷ 전역변수 : 클래스에 포함된 변수

      ① 멤버변수(인스턴스 변수) : 객체마다 존재

      ② 클래스변수(static변수) : 클래스마다 존재, 공유의 목적

▷ 지역변수 : 메소드에 포함된 변수

 

☞ 인스턴스 변수, 지역 변수의 차이점

public class IPhone13 {
	//인스턴스변수
	private String name;
	private String phone;
	
	//매개변수로 넘어온 name -> 지역변수
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setPhone(String phone) {
		this.phone = phone;
	}
	
	public String getPhone() {
		return phone;
	}
}

클래스에서 선언한 name, phone은 인스턴스 변수이며, 메소드에서만 생존하는 매개변수로 넘어온 name은 지역변수입니다.

두 변수의 가장 큰 차이점은 생성되는 메모리 위치에 있습니다. (인스턴스 변수, 지역변수만)

 

인스턴스 변수힙 메모리의 객체 내부에 위치

지역 변수스택 메모리에 위치합니다.

 

메모리 구조를 확인해보겠습니다.

IPhone13 hongPhone = new IPhone13();

우선 객체만 생성하였을 때 (IPhone13 hongPhone = new IPhone13())의 메모리 구조는 위와 같습니다.

heap메모리에 객체가 생성되고 인스턴스 변수 공간이 생성되었지만 값 대입 전이므로 기본 값인 'null'이 들어가있습니다.

hongPhone.setName("홍길동")

IPhone13의 setName메소드를 실행하였으므로 stack메모리에는 setName메소드가 생성되었습니다.

매개변수 name에 "홍길동"을 넘겨 받았으므로 지역변수 name의 공간이 생성되었습니다.

(name 공간 내에는 참조변수가 넘어오지만 우선 "홍길동"이 넘어온 것으로 하겠습니다!)

this.name = name;  현재 객체의 name이라는 공간에 매개변수로 넘어온 name의 값을 대입하라고 하였습니다.

this에는 객체를 가리키는 위치값이 넘어오게 되어 객체에 위치한 인스턴스 변수 name공간을 가리키게 되어 인스턴스 변수 공간에 넘겨 받은 "홍길동"이 대입 된 것을 알 수 있습니다.

 

hongPhone.setPhone("01012341234")

setName메소드가 끝났기 때문에 stack메모리에서 사라졌으며,

setPhone메소드도 동일한 구조를 갖고 인스턴스 변수 공간에 넘겨받은 "01012341234"를 대입하였습니다.

 

☞ 클래스 변수(static 변수)

//static변수
public static int WIDTH = 10;
public static int HEIGHT = 20;
public class IPhone13Main {
	public static void main(String[] args) {
		IPhone13 hongPhone = new IPhone13();
		hongPhone.setName("홍길동");
		hongPhone.setPhone("01012341234");
		System.out.println("이름 : " + hongPhone.getName());
		System.out.println("번호 : " + hongPhone.getPhone());
		
//		IPhone13.WIDTH = 13;
		System.out.println(IPhone13.WIDTH);
		
		IPhone13 sinPhone = new IPhone13();
		sinPhone.setName("신사임당");
		sinPhone.setPhone("01098769876");
		System.out.println("이름 : " + sinPhone.getName());
		System.out.println("번호 : " + sinPhone.getPhone());
		System.out.println(IPhone13.WIDTH);
	}
}

@콘솔출력값
이름 : 홍길동
번호 : 01012341234
10
이름 : 신사임당
번호 : 01098769876
10

static 제어자는 객체 생성 없이 바로 사용 가능하므로, '클래스.멤버명'으로 바로 사용 가능합니다.

static변수는 클래스 내부에 저장 공간을 지니고 있기 때문에 객체 생성 없이 바로 사용할 수 있다는 것입니다.

 

메모리 구조 확인해보겠습니다.

실제 저장 공간은 static 영역 내부에 있으며, 객체 내부의 WIDTH/HEIGHT에는 실제 저장공간의 참조값만 포함하고 있습니다.

또한 static 공간의 클래스 내부에 생성되는 것이므로 클래스 이용 직전에 메모리 적재가 됩니다. (가장 빠름!)

 

클래스 변수(static변수)가장 큰 특징은 공유의 목적을 갖습니다.

객체 내부에는 위치값을 저장한다고 하였습니다.

따라서 각 객체마다 WIDTH/HEIGHT의 위치값을 갖고 있는 공간이 할당되므로 똑같은 값을 가리키고 있게 됩니다.

 

public class IPhone13Main {
	public static void main(String[] args) {
		IPhone13 hongPhone = new IPhone13();
		hongPhone.setName("홍길동");
		hongPhone.setPhone("01012341234");
		System.out.println("이름 : " + hongPhone.getName());
		System.out.println("번호 : " + hongPhone.getPhone());
		
		hongPhone.WIDTH = 13;	//참조변수.멤버명 사용은 지양!!!
		System.out.println(hongPhone.WIDTH);	//IPhone13.WIDTH로 사용해야함
		
		IPhone13 sinPhone = new IPhone13();
		sinPhone.setName("신사임당");
		sinPhone.setPhone("01098769876");
		System.out.println("이름 : " + sinPhone.getName());
		System.out.println("번호 : " + sinPhone.getPhone());
		System.out.println(sinPhone.WIDTH);
	}
}


@콘솔출력값
이름 : 홍길동
번호 : 01012341234
13
이름 : 신사임당
번호 : 01098769876
13

hongPhone의 WIDTH의 값을 변경하였더니 sinPhone의 WIDTH도 변경된 값이 적용된 것을 확인할 수 있습니다.

(static변수는 클래스명.멤버명으로 사용해야하지만 이해를 돕기 위해 참조변수.멤버명으로 값 출력을 했습니다.)

 

이렇듯 공유 기능을 갖고 있기 때문에 일반적으로는 상수로써 사용한다고 합니다.

public static final int WIDTH = 10;
public static final int HEIGHT = 20;

저는 여기서 의문이 생겼습니다. 어차피 변하지 않는 값으로 지정하는 거 왜 굳이 static변수로 사용할까....?

그냥 순수 상수로써 사용하면 안되는 것인가? (final int WIDTH)

→ 그렇게 되면 매번 객체가 생성될 때마다 상수 값을 가진 공간이 생성될 것입니다. 공간의 낭비가 되니 static영역에 한 번 값을 대입하고 그 값을 각 객체가 공유하게끔 사용하는 것이 더 좋을 것입니다.

 

학생 정보 출력 시스템 만들기

public class CEStudent {
	public static final String ACED_NAME = "코린이의 코딩 학습기";
	public static final String COURSE_NAME = "코린이 탈출";
	public static final String HALL_NAME = "티스토리";
	
	private String name;
	private String phone;
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setPhone(String phone) {
		this.phone = phone;
	}
	
	public String getPhone() {
		return phone;
	}
	
	public void print() {
		System.out.println("===============================");
		System.out.println("교육원명 : " + CEStudent.ACED_NAME);
		System.out.println("과정명 : " + COURSE_NAME);
		System.out.println("강의장명 : " + HALL_NAME);
		System.out.println("이름 : " + this.name);
		System.out.println("전화번호 : " + phone);
		System.out.println("===============================");
		
	}
}
package com.ce.java;

public class CEStudentMain {
	public static void main(String[] args) {
		CEStudent stu = new CEStudent();
		stu.setName("홍길동");
		stu.setPhone("01012341234");
		stu.print();
		System.out.println();
		
		CEStudent chae = new CEStudent();
		chae.setName("박채니");
		chae.setPhone("01098769876");
		chae.print();
	}
}

@콘솔출력값
===============================
교육원명 : 코린이의 코딩 학습기
과정명 : 코린이 탈출
강의장명 : 티스토리
이름 : 홍길동
전화번호 : 01012341234
===============================

===============================
교육원명 : 코린이의 코딩 학습기
과정명 : 코린이 탈출
강의장명 : 티스토리
이름 : 박채니
전화번호 : 01098769876
===============================

변하지 않고, 동일한 값은 static final 변수로 선언하였습니다.

 

LIST