반응형
우아한테크코스 1주차 프리코스 과제인 숫자 야구 게임이 끝나고 코드 리뷰를 하면서 private static
메서드를 발견했다.
접근 제한자부터 static
과 메모리 구조까지 기초 개념들을 다시 확실하게 정리하고자 여러 블로그와 자료를 참고하여 정리한다.
참고한 자료들은 하단 참고자료란에 모두 기재해두었다.
접근 제한자
우선 접근 제한자의 종류는 다음과 같다.
접근 제한자 | 적용 대상 | 접근 가능 대상 |
public | 클래스 / 필드 / 생성자 / 메서드 | 모든 대상 |
protected | 필드 / 생성자 / 메서드 | 같은 패키지 또는 자식 클래스 |
default | 클래스 / 필드 / 생성자 / 메서드 | 같은 패키지에 소속된 클래스 |
private | 필드 / 생성자 / 메서드 | 클래스 내부 |
Static 키워드
사전적 정의
정적인, 고정된
자바에서의 Static
Static
키워드를 사용한다는 것은 메모리에 한 번 할당되어 프로그램이 종료될 때 해제되는 것을 의미한다.
Static 메모리
- 일반적으로 생성한 Class - Static 영역에 생성
new
연산을 통해 생성한 객체 - Heap 영역에 생성
객체 생성 시 할당된 Heap 영역의 메모리는?
GC(Garbage Collector)를 통해 수시로 관리받는다.
Static 키워드를 통해 Static 영역에 할당된 메모리는?
- 장점 - 모든 객체가 공유하는 메모리
- 단점 - GC의 관리 영역 밖에 존재 → 프로그램을 종료할 때까지 메모리가 할당된 채로 존재 → 자주 사용 시 시스템의 성능에 악영향
Static 변수의 특징
Static
변수는 클래스 변수이다.- 객체를 생성하지 않고도 Static 자원에 접근 가능
Static 변수와 static 메서드는 Static 메모리 영역에 존재하므로 객체가 생성되기 이전에 이미 할당되어 있다. 따라서 객체의 생성없이 바로 접근하여 사용할 수 있다.
public Class Calculator {
public static String calculatorName = "PraoCalculator";
public static int plus(int x, int y) {
return x + y;
}
public int minus(int x, int y) {
return x - y;
}
}
Calculator.plus(5, 4); // static 메서드이므로 객체 생성없이 사용 가능
Calculator.minus(3, 2); // 에러. static 메서드가 아니므로 객체 생성 후 사용 가능
Calculator praoCal = new Calculator(); // 객체 생성
praoCal.plus(7, 6); // 가능. but 권장되지 않음
praoCal.minus(5, 4); // 객체를 생성하였으므로 사용 가능
Static 변수(정적 변수)
메모리에 고정적으로 할당되어, 프로그램이 종료될 때 해제되는 변수
Java에서 Static 변수란?
- 메모리에 한 번 할당되어 프로그램이 종료될 때 해제되는 변수
- 메모리에 한 번 할당되므로 여러 객체가 해당 메모리를 공유
[예시] 세상의 모든 자동차의 이름이 Ferrari라고 가정
public class Car {
private String name = "Ferrari";
public void printName() {
System.out.println(this.name);
}
}
위 코드의 문제점은?
- 10000개의
Car
객체를 생성하면, "Ferrari"라는 같은 값을 갖는 메모리가 10000개 중복해서 생성
→ 이러한 경우static
을 사용해서 여러 객체가 하나의 메모리를 참조하도록 하면 메모리 효율이 높아진다. - "Ferrari"라는 이름은 결코 변하지 않는 값 →
final
키워드를 붙여준다. - 일반적으로
Static
은 상수의 값을 갖는 경우가 많다 →public
을 선언하여 사용한다.
위와 같은 이유로 일반적으로 static
변수는 public
및 final
과 함께 사용되어 public static final
(상수)로 활용된다.
Static 메서드(정적 메서드)
특징
Static
method는 객체의 생성없이 호출 가능- 객체에서는 호출이 가능은 하지만 지양할 것
- 유틸리티 관련 함수들은 여러 번 사용된다 →
static
메서드로 구현하는 것이 적합 - Util Class의 대표적인 예시 -
java.util.Math
[예시] java.util.Math
public class MathTest {
private String name1 = "Prao";
private static String name2 = "Prao";
public static void printMaxValue(int x, int y) {
System.out.println(Math.max(x, y));
}
public static void printName() {
// System.out.println(name1); // 에러 발생. 불가능한 호출
System.out.println(name2);
}
}
- 두 수의 최댓값을 구하는 경우 Math 클래스의
static
메서드로 선언된max
함수를 초기화 없이 사용
→ 하지만static
메서드에서는static
이 선언되지 않은 변수에 접근이 불가능하다
→ 메모리 할당과 연관지어 생각하면 당연
static 메서드에서 static이 선언되지 않은 변수에 접근하지 못하는 이유
MathTest.printName()
을 사용하려 할 때name1
은new
연산을 통해 객체가 생성된 후에 메모리가 할당된다.- 하지만
static
메서드는 객체의 생성없이 접근하는 함수이다. - 따라서 할당되지 않은 메모리 영역에 접근을 하므로 여기서 문제가 발생한다.
static 메서드에 접근하기 위한 변수는 반드시 static 변수로 선언되어야 한다.
실제 Static 변수와 Static 메서드의 활용
Static 변수
- 일반적으로 상수들만 모아서 사용
- 상수의 변수명은
알파벳 대문자
와_
를 조합해서 사용 - 상속을 방지하기 위해
final class
로 선언
[예시] 숫자 야구 게임에서 재시작 또는 종료에 해당하는 상수 값 클래스
public final class GameCommand {
public static final String RETRY_GAME = "1";
public static final String EXIT_GAME = "2";
}
Static 메서드
- 상속을 방지하기 위해
final class
로 선언 - 유틸 관련 함수들을 모아둔다
[예시] 숫자 야구 게임에서 정수형 숫자를 정수형 배열로 변환 역할을 수행하는 컨버터
public class Converter {
private static final String INT_SEPARATOR = "";
private Converter() {}
public static List<Integer> convertIntToList(int number) {
return Arrays.stream(String.valueOf(number).split(INT_SEPARATOR))
.map(Integer::parseInt)
.toList();
}
}
그래서 언제 private static이 필요할까?
[예시] 학생 클래스
public class Student {
String name;
public Student(String name) {
this.name = name;
}
public void study() {
// TODO 수학 공부
// TODO 국어 공부
}
private void studyMath() {
// TODO 수학 문제집을 펼친다
// TODO 수학 문제를 푼다
// TODO 수학 책을 접는다
}
private void studyKorean() {
// TODO 국어 책을 편다
// TODO 국어 지문을 읽는다
// TODO 국어 책을 접는다
}
}
분석
study()
는public
접근자를 가진다 → 다른 클래스 파일에서도 사용이 가능하다study()
구현부의 수학 공부와 국어 공부 →Student
클래스 내에서만 사용이 가능하다
→private
method로 선언한다
private static은?
study()
가static
함수라면studyMath()
와studyKorean()
도static
이어야 한다 →private static
을 사용하는 것 뿐이다.
public class Student {
String name;
public Student(String name) {
this.name = name;
}
public static void study() {
// TODO 수학 공부
// TODO 국어 공부
}
private static void studyMath() {
// TODO 수학 문제집을 펼친다
// TODO 수학 문제를 푼다
// TODO 수학 책을 접는다
}
private static void studyKorean() {
// TODO 국어 책을 편다
// TODO 국어 지문을 읽는다
// TODO 국어 책을 접는다
}
}
결론
하위 private를 포함하는 상위 메서드가 static으로 선언되었다면,
static 메서드에서 호출하는 하위 메서드 또한 static으로 선언되어야 한다.
참고자료
https://coding-factory.tistory.com/524
https://mangkyu.tistory.com/47
반응형
'Java' 카테고리의 다른 글
[Java] List<? extends Parent> list에 add가 불가능한 이유 (2) | 2024.01.25 |
---|---|
[JUnit - 1] Junit 5란 무엇인가? (어노테이션, 정의, 테스트 클래스와 메서드) (0) | 2023.11.01 |
[Java] 클래스 내의 public 변수와 getter 메서드의 대체 방법 (1) | 2023.10.25 |
[Java] private 생성자의 사용 이유, final, 자바 메모리 구조 (0) | 2023.10.25 |
[Java] 익명클래스, 람다와 스트림 (1) | 2023.10.11 |