728x90
반응형
static
정적(static) 멤버 변수 = 클래스 멤버 변수
- 클래스가 메모리(메서드 영역)에 로딩될 때 함께 로딩되는 멤버변수
- 인스턴스 생성과 상관없음 인스턴스 생성 없이 클래스명만으로 접근 가능 클래스명.정적멤버변수명 또는 클래스명.정적메서드명()
- 정적 멤버변수의 경우 모든 인스턴스에서 하나의 값을 공유함 공유 메모리 공간을 사용하므로 모든 인스턴스가 주소값 공유
- 로컬변수는 메서드 호출 및 종료와 관계있고 인스턴스변수는 인스턴스 생성 및 소멸과 관계있고, 클래스변수는 클래스 로딩(프로그램 시작) 및 클래스 제거(프로그램 종료)와 관계있다.
class StaticEx {
static int a = 10; // 클래스(static = 정적) 멤버변수 선언
int b = 20; // 인스턴스 멤버변수 선언
}
// StaticEx 클래스의 클래스(정적) 변수 a 는
// 클래스가 메모리에 로딩될 때 함께 로딩되므로
// 인스턴스 생성 전에 메모리에 로딩되며, 인스턴스 생성 없이도
// 클래스명만으로 접근 가능한 멤버이다!
System.out.println("StaticEx.a = " + StaticEx.a); // 접근 가능
// System.out.println("StaticEx.b = " + StaticEx.b); // 오류 발생!
// => 인스턴스 멤버변수 b는 반드시 인스턴스를 통해서만 접근 가능!
// StaticEx 클래스의 인스턴스 생성
StaticEx se = new StaticEx();
// => 인스턴스 생성 시 Heap 영역에 인스턴스 멤버도 함께 로딩됨
System.out.println("se.a = " + se.a);
// => 정적 멤버변수도 일반 인스턴스 멤버변수처럼 접근할 수 있으나
// 가급적 static 접근 방식(클래스명.변수명)으로 접근하도록 하자!
System.out.println("se.b = " + se.b); // 반드시 인스턴스를 통해 접근
// 변수 a의 값을 100으로 변경, b의 값을 200으로 변경 후 출력
// se.a = 100;
StaticEx.a = 100;
se.b = 200;
System.out.println("변경 후 StaticEx.a = " + StaticEx.a);
System.out.println("변경 후 se.a = " + se.a);
System.out.println("변경 후 se.b = " + se.b);
System.out.println("==============================");
StaticEx se2 = new StaticEx();
// 인스턴스를 새로 생성하더라도 정적 멤버변수는
// 하나의 메모리 공간을 모든 인스턴스에서 공유하므로
// 하나의 인스턴스에서 값을 변경하면 모든 인스턴스가 변경된 값을 공유
System.out.println("se2.a = " + se2.a); // 변경된 100 이 출력됨
System.out.println("se2.b = " + se2.b); // 새 인스턴스 값 20 출력됨
System.out.println("==============================");
// 대표적인 static 멤버변수의 예
// 수학관련 기능을 제공하는 Math 클래스의 멤버변수는 모두 static
double pi = 3.1415926535;
System.out.println("파이값 : " + pi);
// Math 클래스에 상수 PI 가 제공되며 static 멤버변수로 제공됨
// => 별도의 인스턴스 생성없이 클래스명만으로 접근 가능
System.out.println("파이값 : " + Math.PI);
// 정수를 다루는 Integer 클래스의 멤버변수는 모두 static
System.out.println("INT형 표현범위 최소값 : " + Integer.MIN_VALUE);
System.out.println("INT형 표현범위 최대값 : " + Integer.MAX_VALUE);
정적(static) 메서드
- 메모리 로딩 시점은 정적 멤버변수와 동일함
- 호출 방법도 정적 멤버변수와 동일함
- 메서드 정의 시 리턴타입 앞에 static 키워드를 붙여서 정의
- static 메서드 내에서는 레퍼런스 this 사용 불가!
레퍼런스 this 에 저장되는 인스턴스 주소는 인스턴스가 생성되는 시점에서 만들어지므로 static 멤버가 로딩되는 시점에서는 접근 불가능하다! - static 메서드 내에서는 인스턴스 변수 사용 불가!
레퍼런스 this 사용 불가 사유와 동일함
class StaticEx2 {
public void normalMethod() {
System.out.println("일반 메서드 normalMethod()");
}
public static void staticMethod() {
System.out.println("정적 메서드 staticMethod()");
}
}
class StaticEx3 {
// static 멤버변수와 static 메서드 정의 시 주의사항!
private static int a = 10; // 클래스 로딩 시(인스턴스 생성 전) 함께 로딩됨
private int b = 20; // 인스턴스 생성 시 로딩됨
// ====================================
// static 멤버변수 a 를 리턴하는 Getter 메서드 정의
public static int getA() {
return a;
}
// static 멤버변수 a의 값을 전달받아 초기화하는 Setter 메서드 정의
public static void setA(int a) {
// static 메서드 내에서는 레퍼런스 this 사용 불가!
// => 레퍼런스 this 에 저장되는 인스턴스 주소는
// 인스턴스가 생성되는 시점에서 만들어지므로
// static 멤버가 로딩되는 시점에서는 접근 불가능하다!
// this.a = a; // 오류 발생!
// 레퍼런스 this 대신 클래스명을 통해 접근하면 된다!
StaticEx3.a = a;
}
public static void print() {
// static 메서드 내에서는 인스턴스 멤버변수 사용 불가
// => 클래스(static 멤버) 로딩 시점에서는
// 인스턴스 멤버는 생성되기 전이기 때문(this 와 이유가 동일)
System.out.println("a = " + a);
// System.out.println("b = " + b); // 오류 발생! 접근 불가!
StaticEx3 ex = new StaticEx3();
System.out.println("ex.b = " + ex.b);
}
// ====================================
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
}
// 인스턴스 생성 전 클래스명을 사용하여 멤버메서드 호출
StaticEx2.staticMethod(); // 정적 멤버 메서드 호출 가능
// StaticEx2.normalMethod(); // 인스턴스 멤버 메서드는 호출 불가능
// 인스턴스 생성 후 멤버메서드 호출
StaticEx2 se = new StaticEx2();
se.normalMethod();
se.staticMethod(); // 인스턴스 통해 접근해서 메서드 호출도 가능하나
// 클래스명으로 접근하는 것을 권장함
System.out.println("=============================");
// static 멤버도 private 접근제한자 사용 시 외부클래스에서 접근 불가
// System.out.println("StaticEx3.a = " + StaticEx3.a); // 오류 발생
// 따라서, Getter/Setter 를 사용하여 static 멤버에 접근해야함
// => 만약, 일반메서드로 정의할 경우 클래스명만으로 접근 불가능하며
// 인스턴스 생성을 통해서만 접근해야함
StaticEx3 ex3 = new StaticEx3();
System.out.println("ex3.getA() = " + ex3.getA());
// static 메서드로 정의 시 클래스명만으로 접근이 가능해진다!
System.out.println("StaticEx3.getA() = " + StaticEx3.getA());
System.out.println("========================================");
// static 메서드 활용 예
// => Math 클래스의 모든 메서드는 static 메서드로 제공됨
// 수학관련 기능이 필요할 경우 클래스명만으로 메서드 호출 가능
System.out.println("-5 의 절대값 : " + Math.abs(-5));
static 멤버(클래스 멤버)와 인스턴스 멤버의 생성 시점 차이
- static 멤버는 클래스 내에서 위치와 상관없이 순차적으로 로딩됨
- static 멤버(main() 메서드 포함) 로딩이 끝난 후 main() 메서드 호출됨
- main() 메서드 내에서 인스턴스 생성 시 인스턴스 멤버가 로딩
- 인스턴스 멤버 로딩이 끝난 후 생성자 호출됨
public class Ex {
public int b = callB();
// => 인스턴스 생성 시점에 로딩되어 callB() 메서드를 호출(4번)
public static int a = callA();
// => 클래스 로딩 시점에 로딩되어 callA() 메서드를 호출(1번)
public Ex() { // => 인스턴스 생성 시점에 로딩
// 모든 인스턴스 멤버가 로딩된 후 호출됨(5번)
System.out.println("Ex 클래스의 인스턴스 생성됨!");
}
public static int callA() { // => 클래스 로딩 시점에 로딩
System.out.println("static 변수 a 로딩!");
return 0;
}
public int callB() { // => 인스턴스 생성 시점에 로딩
System.out.println("인스턴스 변수 b 로딩!");
return 0;
}
public static void main(String[] args) { // => 클래스 로딩 시점에 로딩
// => 단, 로딩시점에 호출되지는 않는다!
// => 모든 static 멤버의 로딩이 끝난 후 자동으로 main() 메서드 호출
System.out.println("main() 메서드 호출됨!"); // 3번
Ex ex = new Ex(); // 인스턴스 생성
}
public static int c = callC();
// => 클래스 로딩 시점에 로딩되어 callC() 메서드를 호출(2번)
public static int callC() { // => 클래스 로딩 시점에 로딩
System.out.println("static 변수 c 로딩!");
return 0;
}
}
싱글톤 디자인 패턴 Singleton Design Patter
- 프로그램에서 단 하나뿐인 유일한 객체(인스턴스) = 싱글톤 객체
- 싱글톤 객체를 사용하여 프로그램을 작성하는 기법을 싱글톤 디자인 패턴이라고 한다.
- 새로운 인스턴스 생성이 불가능하게 하며, 미리 생성된 하나의 인스턴스를 모든 참조변수에서 공유해서 사용
싱글톤 패턴 작성 순서
- 객체가 생성되면 안되기 때문에 외부에서 생성자 호출을 못하도록 생성자 정의 시 접근제한자를 private 으로 선언
- 자신의 클래스 내에서 직접 객체를 생성하여 참조변수에 저장 참조변수의 접근제한자를 private 으로 선언하여 접근 제한 참조변수를 static 변수로 선언하여 객체 생성 없이 로딩
- 생성된 인스턴스를 외부로 리턴하는 Getter 를 정의 static 변수를 리턴하므로 Getter 메서드도 static 으로 선언
class SingletonClass {
// 1. 생성자의 접근제한자를 private 으로 선언하여
// 외부에서 인스턴스 생성(생성자 호출)을 못하도록 제한
private SingletonClass() {}
// 2. 자신의 클래스 내에서 직접 인스턴스를 생성하여 참조 변수에 저장
// => 이 때, 인스턴스 생성이 불가능하므로 인스턴스 변수 접근 불가능
// 따라서, 인스턴스 생성 없이도 접근 가능하도록 static 으로 선언
// => 또한, 외부에서 변수에 접근하여 함부로 값을 변경하지 못하도록
// 접근제한자를 private 으로 선언
private static SingletonClass instance = new SingletonClass();
// 3. 인스턴스 생성 후 인스턴스가 저장된 멤버변수도
// 접근제한자로 인해 외부에서 접근이 불가능하므로
// 대신 인스턴스를 리턴해주는 Getter 메서드 정의(Setter 불필요)
// => 이 때, 인스턴스 생성 없이도 호출 가능하도록 static 으로 선언
public static SingletonClass getInstance() {
return instance;
}
}
// 접근제한자가 private 으로 선언된 생성자 호출이 불가능하므로
// SingleClass 의 인스턴스 생성이 불가능해짐
// SingletonClass sc = new SingletonClass();
// SingletonClass sc2 = new SingletonClass();
// static 으로 선언된 정적 멤버변수 instance 에 접근하여
// 미리 생성되어 있는 인스턴스를 가져올 수 있다!
// => 외부에서 함부로 값을 변경할 수 없도록 private 접근제한자 적용
// SingletonClass sc = SingletonClass.instance;
// SingletonClass.instance = null;
// 외부에서 접근할 수 있도록 Getter 메서드를 제공하므로
// Getter 를 호출하여 생성된 인스턴스를 전달받아 사용할 수 있음
// => static 메서드인 getInstance() 메서드를 호출하여 인스턴스 리턴
SingletonClass sc = SingletonClass.getInstance();
// 참조변수 sc2 에도 동일한 인스턴스를 리턴받기
SingletonClass sc2 = SingletonClass.getInstance();
싱글톤디자인패턴 예제
public class Test4 {
public static void main(String[] args) {
// 생성된 인스턴스를 두 번 가져오기
// SingletonTest st = new SingletonTest(); // 인스턴스 생성 불가
SingletonTest st = SingletonTest.getInstance();
SingletonTest st2 = SingletonTest.getInstance();
System.out.println(st.num + ", " + st2.num); // 10, 10 출력
// 인스턴스 내의 인스턴스 변수 값을 변경하면 나머지도 공유됨
st.num = 100;
System.out.println(st.num + ", " + st2.num); // 100, 100 출력
System.out.println("=============================");
JavaTeacher jt = JavaTeacher.getInstance();
JavaTeacher jt2 = JavaTeacher.getInstance();
jt2.teacherName2 = "이순신";
System.out.println(jt.teacherName1 + ", " + jt2.teacherName1);
System.out.println(jt.teacherName2 + ", " + jt2.teacherName2);
}
}
// 1. SingletonTest 클래스 정의 => 싱글톤 디자인 패턴 적용
class SingletonTest {
// 1. 생성자 정의
private SingletonTest() {}
// 2. 인스턴스 생성
private static SingletonTest instance = new SingletonTest();
// 3. Getter 정의
public static SingletonTest getInstance() {
return instance;
}
// ==============================================================
// 싱글톤 패턴으로 생성된 객체 확인을 위한 인스턴스 변수 1개 선언
int num = 10;
}
// 2. JavaTeacher 클래스 정의 => 싱글톤 패턴 적용
class JavaTeacher {
String teacherName1 = "홍길동";
String teacherName2 = "강감찬";
private JavaTeacher() {}
private static JavaTeacher instance = new JavaTeacher();
public static JavaTeacher getInstance() {
return instance;
}
}
728x90
반응형
'프로그래밍 언어 > JAVA' 카테고리의 다른 글
[JAVA] 자바의 인터페이스 Interface (0) | 2021.01.19 |
---|---|
[JAVA] 자바의 상수 Constant (0) | 2021.01.19 |
[JAVA] 자바의 추상 클래스 & 메서드 (0) | 2021.01.19 |
[JAVA] 자바의 참조형변환 (레퍼런스 형변환) (0) | 2021.01.19 |
[JAVA] 자바의 final (0) | 2021.01.19 |