static의 목적은 '공용성'이다.
그리고 static을 활용한 패턴 중 하나가
'싱글톤 패턴'이다.
그러므로 static을 토대로 만든 싱글톤 패턴의 목적 또한 '공용성'이다. 무분별한 객체 생성을 막고 단 한 개만 생성해서 이를 공유하는 것이다. 사무실에 프린터를 한 대만 설치하는 개념이라 생각하면 된다. 직원마다 프린터를 설치하면 돈 낭비이듯, 공용 가능한 객체를 여러 개 생성하면 메모리 낭비이다.
싱글톤 패턴
일단 무분별한 객체 생성부터
막아야 한다.
객체생성은
new 연산자 + 생성자()
로 이루어진다.
생성자()를 private로 설정하여
접근제한을 둔다.
< Singleton.java >
public class Singleton {
private static Singleton slt = new Singleton();
// 클래스 내부에서는 private 생성자 접근 가능
// private로 설정하여 외부 접근 방지
private Singleton() {}
// 외부 객체 생성 방지
public static Singleton getInstance() {
return slt;
// public으로 설정하여 오로지 getInstance()로만 객체 접근 가능하도록 유도
}
}
private static Singleton slt = new Singleton();
객체는 프로그램에 하나만 존재해야한다. 그렇기에 객체의 주소를 담는 참조 변수또한 '단 하나'만 존재해야한다. 그래서 참조 필드를 static으로 선언한다. 이렇게 하면 method 영역에 단 하나만 존재하게 된다.
하지만 static은 어느 곳에서든 참조할 수 있는 공용성을 가진다. 그래서 이를 private로 접근제한을 걸어주어 오로지 클래스 내부에서만 객체생성이 가능하게 만든다.
private static Singleton slt = new Singleton();
이렇게 클래스 내부에 객체 하나가 생성한다. 이 객체를 사용할 프레임들은 getInstance()를 통해 주소를 복사해 가야한다. 이런 원리로 무분별한 객체생성을 방지하여 메모리 낭비를 줄일 수 있다.
하지만 이런 방법은 하나의 객체가 여러 프레임에 영향을 끼쳐 모듈간의 결합성을 훼손시킨다. 이는 객체지향이 선호하는 가치가 아니므로, 메모리 낭비를 줄이자고 무분별한 싱글톤 패턴 사용은 지양해야한다.
public static Singleton getInstance() {}
생성자와 필드를 모두 private로 처리하여 접근을 막음으로써 오로지,
해당 클래스의 객체는 getInstance()가 리턴하는 주소만으로 참조가 가능해진다.
<Main.java>
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Singleton slt1 = Singleton.getInstance();
Singleton slt2 = Singleton.getInstance();
if(slt1==slt2) {
System.out.println("같은 객체 입니다.");
}
else {
System.out.println("다른 객체 입니다.");
}
}
}
<출력 결과>
final
final의 목적은
'수정불가'에 있다.
한번 초기화된 값을 프로그램 실행 중 바뀌지 않도록 강제성을 두어야하는 경우들이 있다. 대한민국 국민의 국적은 KOREA이다. 이를 실행 중 무분별하게 바뀌도록 둔다면 개인의 정보가 크게 훼손될 우려가 있다. 이렇듯 필드가 초기 설정된 값을 유지하도록 강제성을 부여하고 싶다면 final 필드를 사용한다.
그렇다면 만약 final에 static이 붙으면 어떻게 될까?
'수정불가'의 데이터가 '공용성'을 가지는 것이다. 우리는 이를 '상수'라 부른다. 상수는 정해진 값이고 언제든 어디서든 사용가능하다.
<Final.java>
public class Final {
static final double EARTH_SURFACE_AREA;
static {
EARTH_SURFACE_AREA = 4*Math.PI*Math.pow(6400, 2);
}
}
상수를 초기화 시켜준다.
<Main.java>
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(Final.EARTH_SURFACE_AREA);
}
}
라이브러리 클래스 안에 선언된 상수를 사용하기 위해서는 클래스 명과 . 도트 연산자를 통해 클래스를 메모리에 로딩시켜야한다. JVM은 동적 클래스로딩을 지원하기 때문이다.
정리
1. 싱글톤 패턴을 공용성을 위해 사용된다.
2. static과 final이 만나면 상수가 만들어진다.
'JAVA > JAVA Basic' 카테고리의 다른 글
[ JAVA ] JAVA와 C언어의 차이 (0) | 2021.06.18 |
---|---|
[ JAVA ] 상속(Inheritance) (0) | 2021.06.18 |
[ JAVA ] static 알아보기 (0) | 2021.06.18 |
[ JAVA ] 객체의 생성과 호출 (0) | 2021.06.18 |
[ JAVA ] 열거타입(enumeration type) (0) | 2021.06.18 |