레벨 1 레이싱 카 미션을 수행할 때 저는 아래와 같은 질문을 리뷰어에게 남겼습니다.
static 메서드가 메모리를 일반 메서드보다 과하게 사용할 수 있을 것 같은데 static을 최소화하는 것이 좋을까요?
나름대로 좋은 질문이라고 생각했습니다.
정적 메서드
는 객체를 생성하지 않고 클래스를 참조하여 메서드를 호출합니다. 그래서 정적 메서드
는 사용하는 시점에 메서드 메모리 영역에 올라가는 것이 아니라 컴파일 시점에 정적 할당되어 GC의 대상이 되지 않아 프로그램에 끝날 때 까지 메모리에 유지됩니다.
저는 위와 같은 개념을 갖고 질문을 던졌던 것이죠. 하지만 일반 메서드 또한 메서드 메모리 영역에 할당 되기 때문에 정말 많은 정적 메서드
가 존재하지 않는 한 메모리에 큰 차이는 없다고 생각합니다.
하지만 정적 메서드
의 사용은 최소화 하는 것이 좋습니다. 그 이유는 뭘까요?
1. 객체지향적인가?
Java는 객체지향 언어입니다. 객체 지향적인 사고는 아래와 같이 표현할 수 있습니다.
5와 9 중 더 큰 수는 x이다. (객체 지향)
5와 9 중 더 큰수를 계산하라. (절차 지향)
즉 객체지향적인가? 라는 물음의 답변을 어떤 값을 객체에 정의하고 객체들이 필요한 순간에 상호작용하는 것이다라고 정리할 수 있습니다.
하지만 정적 메서드
는 그렇지 않습니다. 객체에 어떤 값을 정의하는 것이 아니라 위의 예시처럼 더 큰 수를 계산하라는 명령을 남깁니다.
따라서 정적 메서드
는 객체 지향적 사고에 어울리지 않는 방식입니다.
2. 객체지향스럽지 않아도 더 빠르잖아?
글의 초입에 말했듯이 정적 메서드
는 객체를 생성하지 않습니다. 클래스를 참조하여 바로 호출해서 사용함으로써 인스턴스를 생성하는 비용을 줄일 수 있어 더 빠르다고 합니다.
하지만 정말 빠른걸까요?
아래 코드를 보겠습니다.
public void do() {
int res = MyCalculator.mul(10, 100);
if(isNeed(res)) {
use(res);
}
}
만약 res
가 필요하지 않다면, res
를 계산하지 않을까요? 아닙니다. 필요, 불필요 여부를 떠나서 무조건 결과값을 계산하겠죠.
하지만 선언형 방식은 어떨까요?
public void do() {
MyCalculator cal = new MyCalculator(10, 100);
if(isNeed(cal)) {
use(cal.mul());
}
}
선언형 방식은 필요한 순간에 계산을 실행합니다. 즉, 컴파일러나 가상머신에서의 최적화 대신 개발자가 직접 코드레벨에서 최적활 할 수 있다는 의미이죠.
이런 측면에서 오히려 정적 메서드
를 사용하지 않고 인스턴스 메서드
를 사용하는 방식이 더 빠르다고 표현할 수 있습니다.
3. 그럼 객체지향 원칙은 잘지키는가?
객체지향적이지 않은 개념이라도 객체지향 원칙을 잘 지킨다면 충분히 사용할 여지가 있습니다. 하지만 정적 메서드
는 객체지향 핵심 원칙 중 하나인 다형성을 지킬 수 없습니다.
다형성은 객체 간 의존성을 느슨하게 만들고 확장에 열려있는 코드를 작성하는 데 큰 힘이 됩니다. 덕분에 유지보수에도 좋은 효과를 주는 아주 고마운 존재이죠.
하지만 정적 메서드
는 메서드 재정의와 동적 바인딩이 불가능 합니다. 즉 인터페이스를 사용할 수 없다는 의미입니다.
다형성을 사용하지 못하는 것이 가독성 차원에서 어떤 문제가 생기는지 본다면 조금 더 쉽게 정적 메서드
사용을 포기할 수도 있습니다.
public static void calculate(int a, int b) {
Scanner scanner = new Scanner();
String x = scanner.nextLine();
if ("더하기".equals(x)) {
System.out.println(a + b);
} else if ("빼기".equals(x)) {
System.out.println(a - b);
} else if ("곱하기".equals(x)) {
System.out.println(a * b);
} else {
System.out.println(a / b);
}
}
굉장히 간단한 코드지만 이 코드가 하는 일을 해석하는 것은 굉장히 귀찮고, 만약 또 다른 조건이 추가된다면 그것을 또다른 분기문으로 처리하는 것이 많이 귀찮아집니다.
하지만 다형성을 사용하고 오버라이딩을 통해 해당 객체에 calculate 메서드를 호출하기만 한다면 원하는 결과가 잘 나오겠죠. (자세한 코드는 생략)
그래서?
저는 객체지향 원칙을 지키기 위해 정적 메서드
사용 자체를 줄이려고 합니다. 하지만 정적 팩터리 메서드
처럼 정적 메서드
의 장점을 잘 이용할 수 있는 순간에는 어김없이 static
키워드를 사용하려 합니다 !
'우아한테크코스 4기 > 레벨1' 카테고리의 다른 글
[레벨 1 돌아보기] dao 테스트 중 lock wait? (0) | 2022.04.15 |
---|---|
[레벨 1 돌아보기] 정적 팩터리 메서드 사용에 대한 고민 (0) | 2022.04.12 |
[Java] @BeforeEach와 독립적인 단위 테스트 (0) | 2022.04.06 |
[Java] db 테스트 (0) | 2022.04.02 |
[Java] JDBC API Statement vs PreparedStatement (1) | 2022.03.29 |