정적변수 간접 체험해보기
앞선 이론편에서 설명한 Static 예약어
클래스 변수 혹은 정적 변수라고 불립니다.
그런데 왜 자바에서는 메인문이 항상
public static void main으로 시작할까요?
아시는 분은 그냥 스킵...
메모리 로딩 순서
변수 | 생성 시기 | 소멸 시기 | 메모리 영역 | 호출 사용법 |
클래스 변수 | 클래스가 메모리에 올라감 | 프로그램 종료 (서버 종료) | 메소드 영역 | 클래스 이름, 인스턴스의 변수 이름 |
인스턴스 변수 | 인스턴스가 생성됌 | 인스턴스가 소멸됌 | 힙 영역 | 인스턴스 이름, 변수 이름 |
지역 변수 | 블록 안에서 변수가 선언됌 | 블록을 나올때 | 스택 영역 | 변수 이름 |
자바의 메모리 로딩 순서는 다음과 같으며 static의 경우에는 클래스 변수에 해당하게 됩니다.
(제가 알기로는 프로그램 시작하면 클래스가 자동으로 메모리 영역에 담겨지는 것으로 알고 있습니다만 ..)
클래스 변수에 접근하기 위해서는
1. 클래스를 통해서 접근
ClassName.class-variable
2. 인스턴스의 변수를 통해서 접근이 가능합니다.
ClassName obj = new ClassName();
obj.class-variable
간단한 예시를 살펴보죠.
예제1
학생 클래스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.rojae.example.student; public class Student { // static 변수를 선언한다 public static int serialNumber = 1000; public int studentID; public String studentName; public int grade; public String address; public String getStudentName() { return this.studentName; } public void setStudentName(String name) { this.studentName = name; } } | cs |
학생 클래스를 생성한 소스코드입니다.
(데이터 전송 객체라고 해도 좋겠네요)
위의 경우 static으로 선언이 되어
클래스 변수인 serialNumber의 값은 1000으로
고정되게 됩니다.
Main 문
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.rojae.example.application; import com.rojae.example.student.Student; public class MainTest { public static void main(String args[]) { Student student1 = new Student(); student1.setStudentName("학생이름1"); System.out.println(student1.serialNumber); // 1000 student1.serialNumber++; // 1001 Student student2 = new Student(); // static serialNumber 공 student2.setStudentName("학생이름2"); System.out.println(student1.serialNumber); // 1001 System.out.println(student2.serialNumber); // 1001 } } | cs |
위의 경우에는 값이 공유되기 때문에
인스턴스 변수인 student1과 student2가
같은 serialNumber를 가진다는 것을 알 수 있습니다.
영원히 죽지 않는 서버라면
데이터베이스의 auto_increment = 1을
이렇게 개발할 수 있겠네요.
(과연 서버 부하는 양호할 것인가)
하지만 아래의 경우에 동작할까요..?
정답은 정상적으로 동작하지 않습니다.
메인 클래스에서 접근이 불가능하기 때문이죠.
하지만 만약에 직접적으로 메인클래스에서
private로 선언된 값을 바꾸려는
다음과 같은 시도가 아니라,
클래스 내부의 메소드를 통해서
값을 증가시켜야 하는 것이죠.
이는 public, private, protected의 차이로 이어집니다.
(접근 제한자는 여기까지만 언급하겠습니다)
예제 2
static 변수가 있다면, static 메소드
즉 클래스 메소드가 존재합니다.
이번에는 serialNumber 변수를 사용하는 메소드를 만들어보고
메모리 로딩 오류에 대해서 예시를 들어보겠습니다.
우선 static 변수를 private로 바꿔주겠습니다.
더불어 static 메소드 (클래스 메소드) 추가를 해주었습니다.
학생 클래스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.rojae.example.student; public class Student { // private로 변경 private static int serialNumber = 1000; public int studentID; public String studentName; public int grade; public String address; public String getStudentName() { return this.studentName; } public void setStudentName(String name) { this.studentName = name; } public static int getSerialNumber() { return serialNumber; } public static void setSerialNumber(int serialNumber) { Student.serialNumber = serialNumber; } } | cs |
Main 문
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.rojae.example.application; import com.rojae.example.student.Student; public class MainTest { public static void main(String args[]) { Student student1 = new Student(); student1.setStudentName("학생이름1"); student1.setSerialNumber(1001); // set 1001 Student student2 = new Student(); // static serialNumber student2.setStudentName("학생이름2"); System.out.println(student1.getSerialNumber()); // 1001 System.out.println(student2.getSerialNumber()); // 1001 } } | cs |
정상적으로 동작하였습니다.
혹시 다음으로 바꿔주면 동작을 할까요..?
학생 클래스 (클래스 메소드 내부의 클래스 인스턴스 변수)
1 2 3 4 | public static int getSerialNumber() { grade = 1; return serialNumber; } | cs |
static 변수에 클래스의 멤버변수 (인스턴스 변수)를 넣어주었지만
에러가 발생한다.
그 이유로는 메모리 로딩 순서가
클래스 변수와 클래스 메소드의 메모리 할당이 이뤄진 이후에
클래스의 인스턴스 변수들도 메모리 할당이 이루어지기 때문이다.
즉 static 메소드는 grade라는 변수를 알 수 없는 것이다.
이때 문제
아래 클래스 메소드에서 static을 제거하면
정상적으로 동작할까..?
마무리
글 쓴다고 아래 같이 하려다 ... 말았습니다..
(글 쓰려 억지로 짜는 소스코드..)
- 다음 글 -
> [Java] 아직입니다 <
'백엔드 > 부족한 기본 정리' 카테고리의 다른 글
[Java 8] 람다식을 사용해보자 How to use lamda (0) | 2020.11.03 |
---|---|
[Java] Overriding 을 막는 세가지 기법 private, static, final (2) | 2020.09.02 |
[Java] static 변수에 대해서 알아보자 (이론편) (0) | 2020.08.24 |
댓글