티스토리 뷰

Static 메서드란?

Static 메서드는 객체 생성 없이 클래스 레벨에서 직접 호출할 수 있는 메서드다.
Java에서 static 키워드를 붙이면 해당 메서드는 객체가 아닌 클래스 자체에 속하는 메서드가 된다.
특정 인스턴스와 관계 없이 클래스 이름만으로 직접 호출할 수 있게 된다.

 

예시: StringUtils 클래스의 static 메서드

public final class StringUtils {
    public static boolean isBlank(String str) {
        return str == null || str.trim().isEmpty();
    }
}

// 호출 예시
boolean result = StringUtils.isBlank(""); // 객체 생성 없이 호출 가능하다!

isBlank 메서드는 StringUtils 클래스에 정의된 static 메서드이다.
객체 생성 없이 클래스 이름을 통해 호출할 수 있다.

 

Static 메서드를 사용하는 이유

1. 독립적인 기능 제공

Static 메서드는 특정 객체의 상태와 무관하게 독립적으로 동작하는 기능을 구현할 때 효과적이다.
예를 들어 문자열 포맷팅, 수학 계산과 같은 비즈니스 로직에서 공통적으로 필요한 유틸리티 기능을 static으로 정의하면 좋다.

public class StringUtils {
    public static String toUpperCase(String input) {
        return input == null ? null : input.toUpperCase();
    }
}

// 호출 예시
String uppercase = StringUtils.toUpperCase("hello");

2. 팩토리 메서드 패턴 활용

객체 생성 로직을 캡슐화 할 수 있다.
객체 초기화 메서드를 static 메서드로 제공하면 가독성 있고, 안전하게 객체를 초기화 할 수 있다.

public class Car {
    private String model;
    private String color;

    // (1) 생성자는 private로 막아놓고
    private Car(String model, String color) {
        this.model = model;
        this.color = color;
    }

    // (2) static 메서드로 객체를 생성한다.
    public static Car createRedCar(String model) {
        return new Car(model, "Red");
    }
}

// 호출 예시
Car redCar = Car.createRedCar("Sedan");

createRedCar 메서드는 Car 객체의 생성 과정에서 기본 색상을 "Red"로 설정해주는 역할을 한다.
이처럼 특정 조건에 맞춘 객체를 생성해야 할 때 static 메서드를 사용하면 명확하고 안전하게 객체를 초기화할 수 있다.

 

Static 메서드 사용은 무조건 옳을까?

위와 같은 장점이 있지만 Static 메서드를 사용할 때는 주의점이 있다.

문제점 1. 다형성 위반

static 메서드는 컴파일 시 정적 바인딩 된다.


다형성은 런타임 중에 객체가 실제로 가리키는 클래스에 따라 동작을 다르게 하는 것이다.

 

자바에서 다형성은 주로 오버라이딩동적 바인딩을 통해서 구현하는데,

static 메서드는 컴파일 시점에 정적 바인딩 되기 때문에 메서드를 동적으로 변경할 수 없어서 오버라이딩도 불가능하다.

 

다형성을 지원하지 않기 때문의 자바의 객체지향과 멀어진다.

 

1. Static 메서드와 오버라이딩

오버라이딩은 자식 클래스에서 부모 클래스를 재정의하고 런타임 중에 자식 클래스의 메서드를 호출하는 것이다.
그런데 static 메서드는 클래스에 속해있기 때문에,

자식 클래스에서 부모 클래스의 static 메서드를 정의해도 오버라이딩이 아닌 메서드 숨김이 된다.

 

예시: static 메서드의 메서드 숨김

public class Parent {
    public static void showMessage() {
        System.out.println("부모 클래스 호출");
    }
}

public class Child extends Parent {
    public static void showMessage() {
        System.out.println("자식 클래스 호출");
    }
}

public class Test {
    public static void main(String[] args) {
        Parent parentInstance = new Parent();
        Parent childInstanceAsParent = new Child();

        parentInstance.showMessage(); // 부모 클래스 호출
        childInstanceAsParent.showMessage(); // 부모 클래스 호출
    }
}

Parent의 showMessage 메서드는 static 메서드이므로,
ParentChild 클래스의 showMessage 메서드는 서로 완전히 독립적이게 된다.

따라서 Child에서 정의된 메서드는 Parent의 메서드를 오버라이딩하지 않고 단지 이름이 같은 메서드를 숨기는 효과만 가지게 된다.

 

Parent 타입 변수로 Child 인스턴스를 참조하더라도, Parent 클래스의 메서드가 호출된다.
정적 바인딩으로 컴파일 시점에 결정되기 때문이다!

 

2. Static 메서드와 인터페이스

자바에서 인터페이스를 구현한 클래스는 메서드를 오버라이딩 할 수 있다.
하지만 static 메서드는 다형성을 지원하지 않기 때문에 인터페이스를 통해 구현될 수 없다.

 

Java 8 이후 인터페이스에서 default 메서드와 static 메서드 정의가 가능해졌지만,
인터페이스의 static 메서드는 인터페이스 자체에서만 접근 가능하고, 상속되지 않고, 다형성에도 영향을 미치지 않는다.

 

public interface StringUtil {
    static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }
}

// 호출 예시
boolean result = StringUtil.isEmpty("test"); // 인터페이스명으로 직접 호출

예시의 StringUtil 인터페이스는 isEmpty static 메서드를 정의하고 있다.
하지만 인터페이스의 메서드이기 때문에 인터페이스명을 통해 직접 호출해야 하고, 이를 구현한 클래스에서 오버라이딩할 수도 없다.

 

3. 정리

정적 메서드는 컴파일 시에 이미 어떤 클래스의 메서드를 호출할지 결정되는 정적 바인딩 방식으로 동작한다.
따라서 static 메서드는 객체 생성 없이 독립적인 기능을 제공할 때 사용하기 적합하다.

 

문제점 2. 메모리 효율

Java 1.8부터는 static 메서드 저장 영역이 Metaspace로 변경되어 GC가 메모리 관리를 할 수 있다.
하지만 클래스가 로드된 상태에서는 static 메모리가 여전히 유지되므로 지나치게 많이 사용하면 메모리 누수가 발생할 수 있다.

 

문제점 3. 테스트와 확장성의 어려움

Static 메서드는 특정 클래스에 강하게 결합되어 있기 때문에 mock 모의 객체로 대체할 수 없어 테스트 코드 작성이 어려워진다.
또 다형성을 활용할 수 없기 때문에 새로운 요구 사항이 추가될 때 변경이나 수정이 어려워질 수도 있다.

 

 

 

결론: 그렇다면 static 메서드는 언제 쓰면 좋을까?

  1. 공통된 기능을 독립적으로 제공할 때
    객체 상태에 영향을 받지 않는 문자열 검증이나 변환 같은 유틸리티 기능에 적합하다.
    StringUtils.isEmpty(String str)와 같은 메서드는 인스턴스 생성 없이 호출할 수 있어 효율적이기 때문에!
  2. 다형성이 필요 없을 때
    객체별로 동작이 다를 수 있는 메서드는 일반 인스턴스 메서드로 작성한다.
  3. 의도적으로 불변성을 제공할 때
    특정 데이터에 고정된 값이 필요하거나, 인스턴스에 종속되지 않도록 해야 할 때 static 메서드를 사용하면 불필요한 객체 생성을 줄이고 고정적인 기능을 만들 수 있다.
  4. 상속이나 인터페이스 구현을 고려할 필요가 없을 때
    static 메서드는 상속관계에서도 메서드가 고정되기 때문에 다형성이 필요한 경우에는 사용하지 않는다.

 

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
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
글 보관함