Welcome! Everything is fine.

[2-1] 클래스와 객체2(3) ~ (4) 본문

자격증 및 기타 활동/J2KB

[2-1] 클래스와 객체2(3) ~ (4)

개발곰발 2021. 8. 19.
728x90

💡 static 변수

static 변수는 여러개의 인스턴스가 같은 메모리의 값을 공유하기 위해 사용한다. 인스턴스가 생성될 때 마다 다른 메모리를 가지는 것이 아니라 프로그램이 메모리에 적재(load)될 때 데이터 영역의 메모리에 생성된다. 사용 방법은 다음과 같다.

static int serialNum;

예를 들어 다음과 같은 학생 클래스가 있고, 각 학생마다 학번을 10000부터 시작하여 1씩 증가시켜 부여하려면 어떻게 해야할까?

public class Student {
	int studentID;
	String studentName;
}

어떤 기준이 되는 숫자(예시에서는 10000)가 있어야 그 숫자에 +1을 해서 학생1에게 주고, 거기서 또 +1을 해서 학생2에게 줄 수 있을 것이다. 다시말해 그 기준이 되는 숫자, 즉 학생1과 학생2가 공통으로 볼 수 있는 값이 필요하다. 그런 값을 대입한 변수를 static으로 선언한다. 다시 아래 예시를 보면, serialNum이라는 static 변수를 선언하고, 10000이라는 값을 대입했다. 또한 학생이 증가할 때 마다 serialNum을 1씩 증가시키기 위해 생성자를 이용하여 serialNum을 1씩 증가시킨 후, 그 값을 studentID에 대입한다.

public class Student {
	static int serialNum = 10000;
	
	int studentID;
	String studentName;
	
	public Student() {
		serialNum++;
		studentID = serialNum;
	}
}

StudentTest1 클래스에서 출력해보면, studentID는 각각 10001, 10002을 출력한다. 그러나 각 인스턴스의 serialNum의 값을 출력해보면 같은 값을 가리키고 있다는 것을 알 수 있다.

public class StudentTest1 {

	public static void main(String[] args) {
		System.out.println(Student.serialNum);
		Student studentJ = new Student();
		System.out.println(studentJ.studentID); // 10001
		
		Student studentT = new Student();
		System.out.println(studentT.studentID); // 10002
		
		System.out.println(studentJ.serialNum);
		System.out.println(studentT.serialNum); // 동시에 같은 값을 가리킴
	}
}

만약 static을 private로 고친다면 serialNum이 객체 외부에 오픈되지 않아 밖에서 사용할 수 없다.  private로 바꿨을때 값을 외부로 가져가기 위해서는 아래와 같이 public static 메서드를 만든다. 단, static 메서드에서는  인스턴스 변수를 사용할 수 없다.

public class Student {
	
	private int serialNum = 10000; 객체 외부에 오픈되지 않음, 밖에서 쓸 수 없음
	
	int studentID;
	String studentName;
    
	public Student() {
		serialNum++;
		studentID = serialNum;
	}
	
	public staitc int getSerialNum() {
		return serialNum;
	}
}

 studentJ와 같은 참조 변수로 쓰지 않고 되도록 static 메서드 이름으로 참조해서 쓴다. 주로 static 변수를 위한 기능을 제공한다. 주의할 점은 static 메서드에서는 인스턴스 변수를 사용할 수 없다는 점이다. 인스턴스 변수는 꼭 new를 이용해 인스턴스가 먼저 생성되어야 하므로 static 메서드에서는 생성이 불확실한 인스턴스 변수를 사용할 수 없다. static 메서드도 인스턴스의 생성과 관계 없이 클래스 이름으로 직접 메서드를 호출한다.

public static void main(String[] args) {
		System.out.println(Student.getSerialNum());
}

 

💡 메모리 영역

프로그램에서 쓰는 메모리 영역은 데이터 영역, 스택 메모리, 힙 메모리 크게 3가지로 나뉜다. 데이터 영역은 static, 리터럴 등이 생성되는 정적 메모리다. 스택 메모리는 지역 변수가 사용하는 메모리로, 선언된 블록 안에서만 유효하다. 힙 메모리는 인스턴스가 생성될 때 마다 사용하는 동적 메모리다. 인스턴스가 생성될 때 메모리를 할당 받고, 인스턴스가 소멸되면 메모리가 사라진다.

💡 변수의 유효 범위

변수 유형 선언 위치 사용 범위 메모리 생성과 소멸
지역 변수(로컬 변수) 함수 내부에 선언 함수 내부에서만 사용 스택 함수가 호출될 때 생성, 함수가 끝나면 소멸
멤버 변수(인스턴스 변수) 클래스 멤버 변수로 선언 클래스 내부에서 사용, private 제외 참조 변수로 다른 클래스에서 사용 인스턴스가 생성될 때 힙에 생성, 가비지 컬렉터가 메모리를 수거할 때 소멸
static 변수(클래스 변수) sttic 예약어를 사용하여 클래스 내부에 선언 클래스 내부에서 사용, private 제외 클래스 이름으로 다른 클래스에서 사용 데이터 영역 프로그램이 처음 시작할 때 상수와 함께 데이터 영역에 생성, 프로그램이 끝나고 메모리를 해제할 때 소멸 

💡 singleton 패턴

객체가 단 하나만 생성될 수 있게 하기 위해 singleton pattern을 사용한다. 아래 코드는 그 예시다. 생성자를 private으로 하고 유일한 인스턴스를 만들어서 이 객체에 접근할 수 있는 public한 메서드를 static으로 제공해야 객체를 생성하지 않고 클래스 이름으로 참조해서 사용할 수 있다.

public class Company {
	
	private  static Company instance = new Company();
	private Company(){
		// 외부에서 이 constructor를 호출하지 못하게 하겠다!라는 의미
	}
	
	public static Company getInstance() {
		if(instance == null)
			instance = new Company();
		return instance;
	}
}
public class CompanyTest {

	public static void main(String[] args) {
		Company c1 = Company.getInstance();
		Company c2 = Company.getInstance();
		
		System.out.println(c1);
		System.out.println(c2);
		// 두 개는 같은 인스턴스를 가리키고 있음
	}
}