컴공댕이 공부일지

[ java를 자바라 ] static / 싱글톤 패턴 / final 본문

기록/EC.crew 정기 모임 정리

[ java를 자바라 ] static / 싱글톤 패턴 / final

은솜솜솜 2023. 5. 8. 20:41
728x90

2023.05.08 EC.crew 정모

 

💙static

new로 생성하지 않는 객체/공유변수에 사용하는 키워드

메모리 static 영역에 만들어져 공유된다!

 

쉽게 말해 다 같이같이 쓰는 건 딱 한번만 생성해두면 되니깐 쓰는 개념이다~

공기는 함께 공유해서 쓰는 자원이니 굳이 공기를 각각의 객체로 공기1, 공기2 이럴 필요가 없다.

아래 예제를 보면 static을 통한 공유를 더 잘 이해할 수 있다.

 

 

🔎 static의 공유적 특성

[ static 사용 x ]

public class staticEx {
	int num = 0;
	staticEx() {
		this.num++;
		System.out.println(this.num);
	}
}
public class Sample {
	public static void main(String[] arts) {
		staticEx s1 = new staticEx();
		staticEx s2 = new staticEx();
	}
}

 >>>

1

1

 

 

각각의 객체에서 공유되지 않고, num이 각각 존재하므로 둘 다 1이 출력된다.

그런데 이 num 변수의 값이 공통적으로 쓰이는 값이라면? (ex. 홈페이지 방문자 수 등)

그러면 매번 저렇게 다른 객체로 생성된 필요 없이 하나로 공유해 쓰면 되는것이다!

 

공유하고 싶은 변수에 static을 붙여보자~ :)

 

[ static 사용 o ]

public class staticEx {
	static int num = 0;
	staticEx() {
		num++;
		System.out.println(num);
	}
}
public class Sample {
	public static void main(String[] arts) {
		staticEx s1 = new staticEx();
		staticEx s2 = new staticEx();
	}
}

>>>

1

2

 

num 앞에 static을 붙였더니, num 값이 하나로 공유되기 때문에 1 2가 출력된다

 

 

 

 

 

🔎 static의 공간적 특성

non-static 멤버는 객체마다 별도로 존재해서 인스턴스 멤버라고 부르지만,

static 멤버들은 클래스 당 하나만 생성되며, 객체 내부가 아닌 별도의 공간(클래스 코드가 적재되는 공간)에 생성된다. 클래스 멤버(=정적 변수) 라고 부른다.

 

또한, static 키워드를 붙이면 자바는 메모리 할당을 딱 한번만 하게 되어 메모리 사용에 이점이 있다.

 

일반적인 클래스는 static 영역에 생성되고, new를 통해 생성한 객체는 heap영역에 생성됨.

힙 영역의 메모리는 Garbage collector를 통해 수시로 관리받음.

그런데 static 영역에 할당된 메모리는 가비지 콜랙터의 관리 영역 밖이라,

프로그램 종료시까지 메모리가 할당된 채로 존재하므로 자주 사용하면 시스템 퍼포먼스에 악영향을 줌.

 

 

 

 

 

🔎 static의 시간적 특성

static 멤버들은 클래스가 로딩될 때 static 공간에 할당됨.

 

non-static 멤버

객체 생성 시 멤버가 생성

  • 객체가 생겨야 멤버도 생성될 수 있음
  • 객체 생성 후에 멤버를 사용할 수 있음
  • 객체가 사라지면 멤버도 사라짐

static 멤버

클래스 로딩 시 멤버 생성. 생성하지 않고 바로 사용가능.

  • 객체가 생기기 전에 이미 생성
  • 객체 생성 전에도 사용 가능
  • 객체가 사라져도 멤버는 안사라짐
  • 멤버는 프로그램 종료 시에 사라짐

 

 

 

 

[ 스태틱 메서드의 활용 : 조회수 카운팅 클래스 ]

public class Counter {

	static int count = 0; 
	//static 안쓰면 에러! 아래 getCount는 스태틱 메서드.
	//스태틱 메서드 안에서 스태틱 변수 아닌 객체 변수에는 접근할 수 없다!
	
	Counter() {
		count++;
		System.out.println(count);
	}
	
	public static int getCount() {
		return count;
	}
}
public class Sample {
	public static void main(String[] arts) {
		Counter c1 = new Counter();
		Counter c2 = new Counter();
		
		System.out.println("조회수 얼마나 되지? ");
		System.out.println(Counter.getCount()); 
		//클래스를 이용해 스태틱 메서드 호출
	}
}

>>>

1
2
조회수 얼마나 되지? 
2

 

스태틱 메서드는 "클래스이름.메서드이름()" 으로

객체 생성없이 클래스를 통해 메서드를 직접 호출할 수 있다.

 

 

 

 

static의 활용

  • 전역 변수와 전역 함수(전역 메소드) 만들 때
  • 공유 멤버 작성할 때

어떤 객체가 단 한 개만 생성되야하는 객체라면? 싱글톤 객체로 구현한다.

 

 

 


 

💙싱글톤 패턴 (singleton pattern) 

 

싱글톤은 단 하나의 객체만을 생성하게 강제하는 디자인 패턴이다.

즉, 클래스를 통해 생성할 수 있는 객체가 딱 하나.

 

접근 제한자 private을 활용해 외부에서 new 연산자로 생성자를 만들 수 없도록 함. ( 클래스 내부에서는 호출 가능! )

#1. private 정적 필드를 하나 선언해 객체 생성&초기화

#2. 외부에서 호출할 수 있는 정적 메소드 getInstance()를 선언하고 정적 필드의 객체를 리턴

( 외부에서 객체를 얻는 유일한 방법은 getInstance() 메소드를 호출하는 것! )

 

public class 하늘 {
	
	//정적 필드 : 생성&초기화
	private static 하늘 푸른하늘 = new 하늘();
	
	//생성자
	private 하늘() {}
	
	//정적 메소드 : 외부에서 호출 가능! => 외부에서 객체를 얻는 유일한 방법~
	static 하늘 getInstance() {
		return 푸른하늘;
	}
}
public class 하늘ex {
	public static void main(String[] args) {
	
		//하늘 a = new 하늘(); 이렇게 생성할 수 없어! 생성자가 private.
		하늘 a = 하늘.getInstance();
		하늘 b = 하늘.getInstance();
		하늘 c = 하늘.getInstance();
		
		if(a==b && b==c) {
			System.out.println("셋은 같은 싱글톤 객체입니다.");
		}
		
	}
}

>> 셋은 같은 싱글톤 객체입니다.

 

 

getInstance() 메소드는 단 하나의 객체만 리턴하기 때문에

위 코드에서 변수 a,b,c는 동일한 하나의 객체를 참조한다.

 

 


 

💙 final 필드

초기값이 저장되면, 프로그램 실행 도중에 수정할 수 없다.

 

final 필드의 초기값을 지정하는 방법은 두 가지가 있다.

1. 필드 선언 시에 초기값 지정

2. 생성자에서 초기값 지정

public class 파이널필드 {
	
	//필드 선언 시 초기값 지정
	final int a = 3;
	final int b;
	
	//생성자에서 초기값 지정
	public 파이널필드 (int x) {
		this.b = x;
	}
	
	//a와 b의 값은 이제 바꿀 수 없다!
}

 

final 필드 = 상수?

final 필드도 한 번 초기화되면 수정할 수 없는데... 상수 아닌가요? => ❌ 아닙니다!

 

상수는 객체마다 저장할 필요 없이 공용성을 띠고, 여러값으로 초기화될 수 없어!

그런데 final 필드는 객체마다 저장되며, 생성자를 통해 여러가지 값을 가질 수 있음.

 

공용성을 띠는 상수는 static이면서 final이어야 한다.

//static final 타입 상수 = 초기갑
static final double PI = 3.141592;

상수는 객체마다 존재하는 것이 아닌, 클래스에만 존재하고, 초기값을 변경할 수 없습니다.

 

 

 

 

 

 

 

 

 

 

*참고

점프 투 자바 - static 예제 참고

혼공자바 교재 - 싱글톤 패턴 참고

728x90
Comments