싱글톤 패턴(Singleton pattern)과 초기화 블록
국비지원수업 14일차
1. 싱글톤 패턴
싱글톤 패턴(Singleton pattern)
유한한 공간안에서 효율적으로 사용하기 위한 방법으로, 단 하나의 new instance를 만들어 놓고 계속 활용하는 방법이다. new instance의 사용은 새롭게 인스턴스를 만드는 과정으로 그만큼의 공간 할당이 필요한데, 싱글톤 패턴을 활용하게 되면 미리 만들어놓은 인스턴스를 새로 만들어지는 객체들이 공유해서 사용하게 되어 공간 절약에 도움을 준다.
1-1. 싱글톤 패턴 방식
싱글톤 방식은
1. 클래스 내부에 유일한 객체(itc)를 private static 형태로 생성해두고
2. public static으로 만들어진 getInstance() 메소드를 호출해서
3. 미리 생성해둔 itc값(객체의 참조값)을 리턴받아 사용하는 방식
이다.
주로 유지되어야 할 정보와 메소드를 많이 갖고 있는 클래스에서 많이 사용하며,
두개의 객체가 유지되면 부담스러운 부분을 하나로 공유하고, 필요한 내용을 멤버 변수로 해결하는 방식이다.
싱글톤 패턴 방식을 코드화 한다면...
1. 생성자를 private로 보호
// 1. 생성자를 private 으로 보호
private SingletonEx() { }
// SingletonEx s1 = new SingletonEx(); // 에러
생성자가 private로 보호되면 외부에서 생성자를 호출해 객체를 만드는 것이 불가능하다. 따라서 무분별한 객체 생성을 방지할 수 있다.
2. 클래스 내부에 유일한 new 인스턴스를 만들어 static 변수에 저장하고
// 2. 클래스 내부에 유일한 new 인스턴스를 만들어서 static 변수에 저장 (이 변수도 private)
private static SingletonEx itc = new SingletonEx();
3. public으로 멤버 메소드를 생성 후 외부에서 리턴 받아 사용
//3. public으로 멤버 메소드를 생성해서 itc 외부에서 리턴받아 사용하게 함
public static SingletonEx getInstance(){
return itc;
}
이를 전체 코드로 본다면...
class SingletonEx{
int n1;
int n2;
private SingletonEx() { }
private static SingletonEx itc = new SingletonEx();
public static SingletonEx getInstance(){
return itc;
}
}
SingletonEx 클래스
SingletonEx s1 = SingletonEx.getInstance();
SingletonEx s2 = SingletonEx.getInstance();
s1.n1 = 100;
s1.n2 = 200;
System.out.println("s1의 n1 : " + s1.n1 + " s1의 n2 : " + s1.n2);
System.out.println("s2의 n1 : " + s2.n1 + " s2의 n2 : " + s2.n2);
main 클래스
공통된 instance 객체 itc 를 각각 s1, s2에 부여함으로서 s1과 s2는 같은 n1, n2 값을 호출하게 되었다.
같은 객체임을 증명하는 방법으로
객체로 완성된 참조변수를 print로 출력하면 '패키지이름.클래스이름@해시코드' 가 출력되는데...
System.out.println(s1);
System.out.println(s2);
객체 s1과 s2를 출력하면 다른 객체와 구분되기 위한 고유코드인 '해시코드' 마저 같은 값으로 출력됨을 알 수 있다.
2. 초기화 블록
우리가 기존에 int a = 100; / classA a = new classA(); 처럼 변수를 선언과 동시에 초기화하는 방식을 많이 사용했다. 이는 가장 기본적이면서도 간단한 '명시적 초기화' 방식이다.
그러나 이보다 복잡한 초기화 작업이 필요할 경우에는 생성자 혹은 초기화 블록을 사용한다.
2-1. 일반 초기화 블록
생성자와 성격이 비슷하게 객체 생성 시 실행된다.
단순 값으로 초기화하는 경우 대입연산자를 통해서 처리할 수 있지만, 실행문이 포함된 초기화를 진행하는 경우 아래와 같이 초기화 과정을 정의할 수 있다.
class InitBlock{
private int number;
// 초기화 블럭
{
number = 100;
System.out.println("인스턴스 변수 초기화 용 초기화 블럭1");
}
}
2-2. static 초기화 블록
static 멤버를 초기화하기 위한 영역으로,
일반 초기화 블록에서는 static 멤버에 자유로운 접근이 가능하지만 static 초기화 블록에서 인스턴스 멤버 접근은 제한된다.
class InitBlock{
static {
System.out.println("InitBlock의 static 블럭 실행");
}
}
실행순서
생성자, 인스턴스 초기화 블록, static 초기화 블록이 모두 있을 때
static 초기화 블록 → 인스턴스 초기화 블록 → 생성자
순으로 실행된다.
class InitBlock{
// 생성자
InitBlock(){
System.out.println("생성자 호출");
}
// 인스턴스 초기화 블럭
{
System.out.println("인스턴스 변수 초기화 용 초기화 블럭1");
}
// static 초기화 블럭
static {
System.out.println("InitBlock의 static 블럭 실행");
}
}
InitBlock 클래스
public static void main(String[] args) {
InitBlock block = new InitBlock();
}
main 클래스
static이니 만큼 InitBlock이 메모리에 로딩될 때 static 초기화 블록이 가장 먼저 수행되고
main 메소드가 수행되어 block 인스턴스가 생성됨에 따라 인스턴스 초기화 블록이 수행되고
마지막으로 생성자가 수행되는 방식이다.
'Backend > Java' 카테고리의 다른 글
[JAVA] 상속 객체 형변환(TypeCasting)과 사용 (0) | 2024.10.16 |
---|---|
[JAVA] 상속(extends)과 super, 오버라이딩(overriding) (0) | 2024.10.15 |
[JAVA] static과 인스턴스(instance) (0) | 2024.10.14 |
[JAVA] 클래스 생성자(Constructor) (0) | 2024.10.14 |
[JAVA] 클래스(Class) 생성과 사용 (0) | 2024.10.07 |