[java] static 변수, static 메소드 란?

반응형

1. static 이란?

static 이란 '정적인', '고정적인' 이라는 사전적 의미를 가진다. 이를 java 관점으로 해석하면 '클래스의' 또는 '공통적인' 이라는 의미를 가진다. static 을 이해하기 위해서는 먼저 JVM (자바 가상 머신) 을 이해할 필요가 있다.

 

◼︎ JVM ( Java Virtual Machine, 자바 가상 머신 )

쉽게 말하면 '자바를 실행하기 위한 가상의 컴퓨터' 라고 할 수 있다.

 

  1. java 애플리케이션을 실행하면 JVM 은 OS 로부터 메모리를 할당한다.
  2. 자바 컴파일러 (javac) 가 자바 소스코드 (Xxx.java) 를 바이트코드 (Xxx.class) 로 컴파일 한다.
  3. 클래스 로더 (Class Loader) 를 통해 JVM 메모리 (Runtime Data Areas) 로 로딩한다.
  4. 로드된 클래스 파일 (Xxx.class) 들은 기계가 읽을 수 없으므로 실행 엔진 (Execution Engine) 을 통해 기계어로 변환하여 실행한다.
  5. 이 과정에서 실행엔진에 의해 가비지 콜렉터 (Garbage Collector) 등도 작동된다.

 

자바 어플리케이션이 실행되면 JVM은 시스템으로부터 필요한 메모리를 할당받고, 용도에따라 여러 영역으로 나누어 관리한다. Method Area, Call Stack, Heap 이 대표적이다. 

 

  • 메소드 영역 (Method Area)
    • JVM 이 클래스 파일 (*.class) 을 읽어 클래스 데이터를 저장하는 영역이다. 이때 클래스 변수도 함께 생성된다.
  • 힙 (Heap)
    • 인스턴스가 생성되는 공간이다. 프로그램 실행 중 new 연산으로 생성되는 인스턴스 변수들이 생성된다.
  • 호출 스택 (Call Stack)
    • 메소드의 작업에 필요한 메모리 공간을 제공한다. 메소드가 호출되면 호출 스택에 메모리가 할당되고 해당 메소드가 수행되는 동안 필요한 값 등을 저장하는데 사용된다. 메소드 실행이 완료되면 할당되었던 메모리 공간은 반환된다.

 

2. static 변수

  • 클래스 변수
  • 한 클래스에서 공통적인 값을 유지해야할때 선언한다.
  • 클래스가 메모리에 로딩될 때 생성되어 프로그램이 종료될 때 까지 유지된다.
  • 객체를 생성하지 않고도 '클래스이름.변수명' 으로 호출이 가능하다.

 

// static 변수 (클래스 변수)
public class MyMathStaticBasic {
    public static final String DESCRIPTION = "static 변수";
}

// 인스턴스 변수
public class MyMathBasic {
    public long a;
    public long b;
    public String description = "인스턴스 변수";
}

 

• 테스트

@Test
@DisplayName("static 변수, 인스턴스 변수")
public void staticStr() {
    //static 변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
    System.out.println("static 변수 출력 = " + MyMathStaticBasic.DESCRIPTION);

    //인스턴스 변수는 인스턴스를 생성해야 사용할 수 있다.
    MyMathBasic mathBasic = new MyMathBasic();
    System.out.println("인스턴스 변수 출력 = " + mathBasic.description);
}

 

• 결과

static 변수 출력 = static 변수
인스턴스 변수 출력 = 인스턴스 변수

 

 

3. static 메소드

  • 클래스 메소드
  • 인스턴스 변수를 사용할 수 없으므로 인스턴스와 관계없는 메소드를 클래스 메소드 (static 메소드) 로 정의한다.
  • 객체를 생성하지 않고도 '클래스이름.메소드명' 으로 호출이 가능하다.

 

// static 변수, static 메소드 (클래스 변수, 클래스 메소드)
public class MyMathStaticBasic {
    public static final String DESCRIPTION = "static 변수";
    
    /** 매개변수로 가능 */
    public static long add(long a, long b) { return a + b; }
    public static long subtract(long a, long b) { return a - b; }
    public static long multiply(long a, long b) { return a * b; }
    public static double divide(long a, long b) { return a / b; }
}

// 인스턴스 변수
public class MyMathBasic {
    long a;
    long b;
    String description = "인스턴스 변수";

    /** 인스턴스 변수 a, b 만 이용하므로 매개변수가 필요없다. */
    public long add() { return a + b; }
    public long subtract() { return a - b; }
    public long multiply() { return a * b; }
    public double divide() { return a / b; }
}

 

 

• 테스트

@Test
@DisplayName("static 메소드")
public void mathStatic() {
    long num1 = 100L;
    long num2 = 10L;
    
    System.out.println("add(num1, num2) = " + MyMathStaticBasic.add(num1, num2));
    System.out.println("subtract(num1, num2) = " + MyMathStaticBasic.subtract(num1, num2));
    System.out.println("multiply(num1, num2) = " + MyMathStaticBasic.multiply(num1, num2));
    System.out.println("divide(num1, num2) = " + MyMathStaticBasic.divide(num1, num2));
    
    assertEquals(110L, MyMathStaticBasic.add(num1, num2));
    assertEquals(90L, MyMathStaticBasic.subtract(num1, num2));
    assertEquals(1000L, MyMathStaticBasic.multiply(num1, num2));
    assertEquals(10.0, MyMathStaticBasic.divide(num1, num2));
}

@Test
@DisplayName("인스턴스 메소드")
public void mathBasic() {
    MyMathBasic mathBasic = new MyMathBasic();
    mathBasic.a = 200L;
    mathBasic.b = 10L;
    
    System.out.println("add() = " + mathBasic.add());
    System.out.println("subtract() = " + mathBasic.subtract());
    System.out.println("multiply() = " + mathBasic.multiply());
    System.out.println("divide() = " + mathBasic.divide());
    
    assertEquals(210L, mathBasic.add());
    assertEquals(190L, mathBasic.subtract());
    assertEquals(2000L, mathBasic.multiply());
    assertEquals(20.0, mathBasic.divide());
}

 

• 결과 (static 메소드)

add(num1, num2) = 110
subtract(num1, num2) = 90
multiply(num1, num2) = 1000
divide(num1, num2) = 10.0

 

• 결과 (인스턴스 메소드)

add() = 210
subtract() = 190
multiply() = 2000
divide() = 20.0

 

 

4. 정리

  1. 클래스를 설계할 때, 멤버 변수 중 모든 인스턴스에 공통으로 사용하는 것에 static 을 선언한다.
  2. 클래스 변수 (static 변수) 는 인스턴스를 생성하지 않아도 호출할 수 있다.
  3. 클래스 메소드 (static 메소드) 는 인스턴스 변수를 사용할 수 없다.
  4. 메소드 내에서 인스턴스 변수를 사용하지 않는다면, static 을 붙이는 것을 고려하자.

 

  • 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있다면 static 을 선언한다.
  • 작성한 메소드 중에 인스턴스 변수나 인스턴스 메소드를 사용하지 않는 메소드에는 static 을 선언할 것을 고려한다.

 

반응형