본문 바로가기
Java

Java | 정적 변수 vs 정적 메서드

by sseul-log 2025. 10. 4.

목차

  1. static이란 무엇인가
  2. 정적 변수(Static Variable)
  3. 정적 메서드(Static Method)
  4. 실무 예제와 메모리 구조
  5. 자주 하는 실수와 해결법

1. static이란 무엇인가?

핵심 개념

static = 클래스 레벨에서 단 하나만 존재하는 공유 자원

Oracle 공식 문서에 따르면:

"Static members belong to the class instead of a specific instance"

 
 
java
public class CoffeeShop {
    // 인스턴스 변수 - 각 점포별로 다름
    private String branchName;
    private int dailySales;
    
    // static 변수 - 모든 점포가 공유
    private static String brandName = "스타벅스";
    private static int totalStores = 0;
    private static double coffeePrice = 4500;
}

메모리 구조 시각화

JVM 메모리 구조
┌────────────────────────────────────┐
│         Method Area (Static)       │
│  ┌─────────────────────────────┐   │
│  │ brandName: "스타벅스"         │   │
│  │ totalStores: 3              │   │
│  │ coffeePrice: 4500           │   │
│  └─────────────────────────────┘   │
└────────────────────────────────────┘
                ↑ 공유
┌─────────────────────────────────────────┐
│                Heap Area                │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│  │ 강남점     │ │ 판교점    │ │ 역삼점     │ │
│  │ sales:50 │ │ sales:30 │ │ sales:40 │ │
│  └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────┘

2. 정적 변수 (Static Variable)

 
실무 예제: 쇼핑몰 배송 시스템
 
java
public class DeliveryService {
    // 인스턴스 변수 - 주문별로 다름
    private String orderId;
    private String address;
    private double weight;
    
    // static 변수 - 전체 시스템 공유
    private static double baseDeliveryFee = 3000;    // 기본 배송료
    private static int totalDeliveries = 0;          // 총 배송 건수
    private static boolean holidayMode = false;      // 공휴일 여부
    
    public DeliveryService(String orderId, String address, double weight) {
        this.orderId = orderId;
        this.address = address;
        this.weight = weight;
        totalDeliveries++;
    }
    
    // 배송료 계산 (인스턴스 메서드)
    public double calculateFee() {
        double fee = baseDeliveryFee;
        if (weight > 5.0) {
            fee += 1000;  // 5kg 초과 시 추가 요금
        }
        if (holidayMode) {
            fee += 2000;  // 공휴일 추가 요금
        }
        return fee;
    }
    
    // 공휴일 설정 (static 메서드)
    public static void setHolidayMode(boolean isHoliday) {
        holidayMode = isHoliday;
        if (isHoliday) {
            System.out.println("공휴일 모드 활성화 - 추가 요금 적용");
        }
    }
}

3. 정적 메서드 (Static Method)

⚠️ 핵심 규칙

static 메서드는 인스턴스 변수/메서드에 접근 불가

 
 
java
public class Calculator {
    private int memory = 0;  // 인스턴스 변수
    
    // ❌ 잘못된 static 메서드
    public static void wrongMethod() {
        memory = 10;  // 컴파일 에러!
        // Cannot make a static reference to non-static field
    }
    
    // ✅ 올바른 static 메서드
    public static int add(int a, int b) {
        return a + b;  // 매개변수만 사용
    }
}

왜 접근이 안 될까? 

시나리오: Calculator.add(5, 3) 호출

┌──────────────────────────┐
│   Static Method 실행      │
│                          │
│   "memory를 사용하라고?"    │
│         ↓                │
│   객체가 없는데?            │
│   누구의 memory?          │
│         ↓                │
│      에러 발생!            │
└──────────────────────────┘

4. 실무 예제: API 요청 제한 시스템

java
public class ApiRateLimiter {
    // 인스턴스 변수 - 사용자별
    private String userId;
    private int userRequestCount;
    private long lastRequestTime;
    
    // static 변수 - 시스템 전체
    private static final int MAX_REQUESTS_PER_MINUTE = 60;
    private static int totalRequestsToday = 0;
    private static boolean maintenanceMode = false;
    
    public ApiRateLimiter(String userId) {
        this.userId = userId;
        this.userRequestCount = 0;
        this.lastRequestTime = System.currentTimeMillis();
    }
    
    // 인스턴스 메서드 - 개별 사용자 요청 처리
    public boolean makeRequest() {
        if (maintenanceMode) {
            System.out.println("시스템 점검 중");
            return false;
        }
        
        if (userRequestCount >= MAX_REQUESTS_PER_MINUTE) {
            System.out.println(userId + ": 요청 한도 초과");
            return false;
        }
        
        userRequestCount++;
        totalRequestsToday++;
        return true;
    }
    
    // static 메서드 - 시스템 관리
    public static void enableMaintenance() {
        maintenanceMode = true;
        System.out.println("점검 모드 활성화");
    }
    
    public static void showStatistics() {
        System.out.println("오늘 총 요청: " + totalRequestsToday);
        System.out.println("분당 제한: " + MAX_REQUESTS_PER_MINUTE);
    }
    
    // 사용 예시
    public static void main(String[] args) {
        ApiRateLimiter user1 = new ApiRateLimiter("user001");
        ApiRateLimiter user2 = new ApiRateLimiter("user002");
        
        user1.makeRequest();  // 개별 요청
        user2.makeRequest();  // 개별 요청
        
        ApiRateLimiter.showStatistics();  // 전체 통계
        ApiRateLimiter.enableMaintenance();  // 시스템 점검
    }
}

메모리 상태 다이어그램

[Static 영역]
┌───────────────────────────────┐
│ MAX_REQUESTS: 60              │
│ totalRequestsToday: 2         │
│ maintenanceMode: false → true │
└───────────────────────────────┘
         ↑            ↑
    ┌────┴────┐  ┌────┴────┐
    │ user1   │  │ user2   │
    │ count:1 │  │ count:1 │
    └─────────┘  └─────────┘

5. 자주 하는 실수와 해결법

❌ 실수 1: static 메서드에서 인스턴스 변수 접근

 
java
public class User {
    private String name;
    
    public static void printName() {
        System.out.println(name);  // 컴파일 에러!
    }
}

 

해결:

java
public static void printName(User user) {
    System.out.println(user.name);  // 객체를 매개변수로 받기
}

❌ 실수 2: 개인정보를 static으로 선언

java
public class Account {
    static String password;  // 위험! 모든 계정이 같은 비밀번호
}

 

해결:

java
public class Account {
    private String password;  // 인스턴스 변수로 변경
    private static String passwordPolicy = "8자 이상";  // 정책은 static
}

최종 정리표

특징 static 변수 static 메서드 인스턴스 변수 인스턴스 메서드
메모리 위치 Method Area Method Area Heap Heap
생성 시점 클래스 로딩 클래스 로딩 new 할 때 new 할 때
개수 1개 1개 객체 수만큼 객체 수만큼
접근 방법 클래스명.변수 클래스명.메서드() 객체.변수 객체.메서드()
this 사용

암기 할 것

static = 공유 = 클래스 소속 = 객체 없어도 OK
인스턴스 = 개별 = 객체 소속 = 객체 필요

static 메서드 → static만 접근 가능
인스턴스 메서드 → 모든 것 접근 가능

참고 자료