일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 30 | 31 |
- Android
- MySQL
- Kotlin
- 인프런
- CS
- 티스토리챌린지
- java
- 코틀린
- 혼공단
- 오블완
- 스터디
- doitandroid
- 정보처리기사
- 정처기
- join
- 안드로이드
- 프로그래머스
- 카카오코테
- 코테
- 혼공챌린지
- 자료구조
- 자바
- 안드로이드스튜디오
- Til
- 알고리즘
- groupby
- select
- 기술면접
- SQL
- 혼공파
- Today
- Total
Welcome! Everything is fine.
[2-1] 클래스와 객체2(3) ~ (4) 본문
💡 static 변수
static 변수는 여러개의 인스턴스가 같은 메모리의 값을 공유하기 위해 사용한다. 인스턴스가 생성될 때 마다 다른 메모리를 가지는 것이 아니라 프로그램이 메모리에 적재(load)될 때 데이터 영역의 메모리에 생성된다. 사용 방법은 다음과 같다.
static int serialNum;
예를 들어 다음과 같은 학생 클래스가 있고, 각 학생마다 학번을 10000부터 시작하여 1씩 증가시켜 부여하려면 어떻게 해야할까?
public class Student {
int studentID;
String studentName;
}
어떤 기준이 되는 숫자(예시에서는 10000)가 있어야 그 숫자에 +1을 해서 학생1에게 주고, 거기서 또 +1을 해서 학생2에게 줄 수 있을 것이다. 다시말해 그 기준이 되는 숫자, 즉 학생1과 학생2가 공통으로 볼 수 있는 값이 필요하다. 그런 값을 대입한 변수를 static으로 선언한다. 다시 아래 예시를 보면, serialNum이라는 static 변수를 선언하고, 10000이라는 값을 대입했다. 또한 학생이 증가할 때 마다 serialNum을 1씩 증가시키기 위해 생성자를 이용하여 serialNum을 1씩 증가시킨 후, 그 값을 studentID에 대입한다.
public class Student {
static int serialNum = 10000;
int studentID;
String studentName;
public Student() {
serialNum++;
studentID = serialNum;
}
}
StudentTest1 클래스에서 출력해보면, studentID는 각각 10001, 10002을 출력한다. 그러나 각 인스턴스의 serialNum의 값을 출력해보면 같은 값을 가리키고 있다는 것을 알 수 있다.
public class StudentTest1 {
public static void main(String[] args) {
System.out.println(Student.serialNum);
Student studentJ = new Student();
System.out.println(studentJ.studentID); // 10001
Student studentT = new Student();
System.out.println(studentT.studentID); // 10002
System.out.println(studentJ.serialNum);
System.out.println(studentT.serialNum); // 동시에 같은 값을 가리킴
}
}
만약 static을 private로 고친다면 serialNum이 객체 외부에 오픈되지 않아 밖에서 사용할 수 없다. private로 바꿨을때 값을 외부로 가져가기 위해서는 아래와 같이 public static 메서드를 만든다. 단, static 메서드에서는 인스턴스 변수를 사용할 수 없다.
public class Student {
private int serialNum = 10000; 객체 외부에 오픈되지 않음, 밖에서 쓸 수 없음
int studentID;
String studentName;
public Student() {
serialNum++;
studentID = serialNum;
}
public staitc int getSerialNum() {
return serialNum;
}
}
studentJ와 같은 참조 변수로 쓰지 않고 되도록 static 메서드 이름으로 참조해서 쓴다. 주로 static 변수를 위한 기능을 제공한다. 주의할 점은 static 메서드에서는 인스턴스 변수를 사용할 수 없다는 점이다. 인스턴스 변수는 꼭 new를 이용해 인스턴스가 먼저 생성되어야 하므로 static 메서드에서는 생성이 불확실한 인스턴스 변수를 사용할 수 없다. static 메서드도 인스턴스의 생성과 관계 없이 클래스 이름으로 직접 메서드를 호출한다.
public static void main(String[] args) {
System.out.println(Student.getSerialNum());
}
💡 메모리 영역
프로그램에서 쓰는 메모리 영역은 데이터 영역, 스택 메모리, 힙 메모리 크게 3가지로 나뉜다. 데이터 영역은 static, 리터럴 등이 생성되는 정적 메모리다. 스택 메모리는 지역 변수가 사용하는 메모리로, 선언된 블록 안에서만 유효하다. 힙 메모리는 인스턴스가 생성될 때 마다 사용하는 동적 메모리다. 인스턴스가 생성될 때 메모리를 할당 받고, 인스턴스가 소멸되면 메모리가 사라진다.
💡 변수의 유효 범위
변수 유형 | 선언 위치 | 사용 범위 | 메모리 | 생성과 소멸 |
지역 변수(로컬 변수) | 함수 내부에 선언 | 함수 내부에서만 사용 | 스택 | 함수가 호출될 때 생성, 함수가 끝나면 소멸 |
멤버 변수(인스턴스 변수) | 클래스 멤버 변수로 선언 | 클래스 내부에서 사용, private 제외 참조 변수로 다른 클래스에서 사용 | 힙 | 인스턴스가 생성될 때 힙에 생성, 가비지 컬렉터가 메모리를 수거할 때 소멸 |
static 변수(클래스 변수) | sttic 예약어를 사용하여 클래스 내부에 선언 | 클래스 내부에서 사용, private 제외 클래스 이름으로 다른 클래스에서 사용 | 데이터 영역 | 프로그램이 처음 시작할 때 상수와 함께 데이터 영역에 생성, 프로그램이 끝나고 메모리를 해제할 때 소멸 |
💡 singleton 패턴
객체가 단 하나만 생성될 수 있게 하기 위해 singleton pattern을 사용한다. 아래 코드는 그 예시다. 생성자를 private으로 하고 유일한 인스턴스를 만들어서 이 객체에 접근할 수 있는 public한 메서드를 static으로 제공해야 객체를 생성하지 않고 클래스 이름으로 참조해서 사용할 수 있다.
public class Company {
private static Company instance = new Company();
private Company(){
// 외부에서 이 constructor를 호출하지 못하게 하겠다!라는 의미
}
public static Company getInstance() {
if(instance == null)
instance = new Company();
return instance;
}
}
public class CompanyTest {
public static void main(String[] args) {
Company c1 = Company.getInstance();
Company c2 = Company.getInstance();
System.out.println(c1);
System.out.println(c2);
// 두 개는 같은 인스턴스를 가리키고 있음
}
}
'자격증 및 기타 활동 > J2KB' 카테고리의 다른 글
[3-1] 오버라이딩과 다형성(3) ~ 다형성 활용과 다운캐스팅(4) (0) | 2021.08.25 |
---|---|
[2-3] 상속과 다형성(1) ~ (2) (0) | 2021.08.21 |
[2-2] 배열과 ArrayList(1) ~ ArrayList 클래스(4) (0) | 2021.08.19 |
[1-2] 클래스와 객체1(4) ~ 2(2) (0) | 2021.08.12 |
[1-1] 클래스와 객체1(1) ~ (3) (0) | 2021.08.10 |