[자바] 선언위치에 따른 변수의 종류 3가지

skyepodium·2021년 12월 26일
7
post-thumbnail

선언위치에 따른 변수의 종류 3가지 1. 클래스 변수, 2. 인스턴스 변수, 3. 지역변수에 대해 알아봅시다.

1. 변수의 종류

0) 개요

자바에서는 선언위치에 따라 변수의 종류가 달라집니다.

class Calculator {
    // 1. 클래스 변수 - 원주율
    static double PI = 3.14;
    // 2. 인스턴스 변수 - 반지름
    double radius = 0;

    public double getAreaOfCircle() {
        // 3. 지역 변수
        double result = this.PI * this.radius * this.radius;

        return result;
    }

    // 생성자 - 반지름을 넣어줍니다.
    Calculator(int radius) {
        this.radius = radius;
    }
}

1) 클래스 변수

static 지시자를 붙이며, 클래스가 메모리에 로딩될 때 생성됩니다.JVM 메모리 영역 중 method 영역에 로드됩니다.

모든 클래스의 객체가 공통된 변수를 공유하게됩니다.

이미 메모리에 올라가 있기 때문에 클래스의 객체를 생성하지 않고도 사용가능합니다.

class Main {
    public static void main(String[] args) {
        // 클래스 변수는 클래스의 객체 생성없이 바로 사용가능합니다. - 3.14
        System.out.println(Calculator.PI);
    }
}

실제로 자바의 Math 클래스의 PI는 static으로 선언되어 있습니다.

이처럼 클래스 변수의 객체를 안만들어도 사용가능하다는 특징으로 인해 유틸성 라이브러리들을 static으로 선언후 클래스의 객체를 생성하지 않고 사용하고 있습니다.

2) 인스턴스 변수

클래스의 객체를 생성할 때 만들어집니다. JVM 메모리 영역중 Heap 영역에 로드됩니다.

클래스의 객체마다 독립적인 값을 가질 수 있습니다.

3) 지역 변수

블럭 내부에서 변수 선언문이 실행되었을 때 생성됩니다. 블럭이 종료되면 소멸됩니다.
JVM 메모리 영역중 Heap 영역에 로드됩니다.

사실, 이제부터가 진짜
HOXY 그런 생각안드시나요? 오 클래스 변수는 공유도 되고 전역으로 사용할 수 있고 객체 안만들고도 사용할 수 있는데 전부다 static 붙여서 클래스 변수로 사용하지뭐

결론은 안됩니다.

2. 자바 메모리 구조

자바가 구동되는 JVM의 Runtime Data Area는 총 5개로 구분됩니다.

1) PC Register - 현재 수행중인 JVM 명령어 저장
2) JVM stack - 호출된 메소드의 매겨변수, 지역변수, 리턴정보 저장
3) Native Method stack - 자바 외 C, C++로 구현된 정보 저장

4) Heap: 런타임 중 생성되는 객체들이 저장
5) Method: 전역변수, 정적변수, 메소드 정보 저장

문제는 Method 영역에 저장된 정보는 가비지 컬렉션의 대상이 되지 않으며, 프로그램이 종료될때 해제됩니다.

가비지 컬렉션에 대해 알아봅시다.

3. 가비지 컬렉션

자바에서는 Garbage Collector가 주기적으로 더 이상 사용하지 않는 메모리를 수집하고 해제하는 역할을 합니다.

문제는 Heap영역에 런타임시 동적으로 할당되는 객체들은 해제가되는데, Method 영역의 정보들은 계속해서 메모리를 점유하고 있다는 것입니다.

그래서 정리하면, 정말 필요한것만 static을 붙여서 클래스 변수로 선언합시다.

4. final

0) 개요

final 지시자는 자바에서 변할 수 없다는 의미로 사용됩니다.

1) 정적 변수

만약 아래처럼 누군가가 PI(원주율)의 값을 222로 바꾼다면, 원의 넓이는 잘못 계산됩니다.

class Main {
    public static void main(String[] args) {
        Calculator calculator = new Calculator(2);
        // 원의 넓이 계산 - 12.56
        System.out.println(calculator.getAreaOfCircle());

        // 클래스 변수 PI 값 변경
        Calculator.PI = 222;
        // 원의 넓이 계산 - 888
        System.out.println(calculator.getAreaOfCircle());
    }
}

class Calculator {
    // 1. 클래스 변수 - 원주율
    static double PI = 3.14;
    // 2. 인스턴스 변수 - 반지름
    double radius = 0;

    public double getAreaOfCircle() {
        // 3. 지역 변수
        double result = this.PI * this.radius * this.radius;

        return result;
    }

    // 생성자 - 반지름을 넣어줍니다.
    Calculator(int radius) {
        this.radius = radius;
    }
}

변하지 않는 값이라면 final을 붙여 생성합니다.

static final double PI = 3.14;

2) 정적 메소드

정적 메소드는 클래스 변수만 접근 할 수 있다는 특징이 있습니다.

왜냐하면 접근하려고 해도 인스턴스 변수는 메모리에 올라와 있지 않을 수 있기 때문에 접근이 막혀있습니다.

그래서 좋은 방법은 함수의 파라미터 변수클래스 변수 만 사용하는 것입니다.

자바 Math 유틸에서 각도를 라디안으로 바꾸는 함수 파라미터와, 클래스변수만 사용합니다.

3) 여담 - 메인 메소드

메인 메소드는 가장 자주보는 정적 메소드중 하나입니다.

public static void main(String []args) {
}

그래서 메인메소드를 제출하는 알고리즘 시험에서는 static으로 전역변수 선언해서 클래스 내부에서 사용했습니다.

그리고,
여러가지 이유가 있겠지만, 제 생각에 메인 메소드를 정적 메소드로 만든 이유는 생성자 때문입니다.

왠만해서 메인 클래스에 생성자를 안넣지만, 정적 메소드가 아니라면, 생성자를 통해 객체를 생성해야하는데, 프로그래머가 생성자를 여러개 만들면 어떤것을 선택해야할지 모르기 때문입니다.

그냥 그렇다구

5. 정리

1) static 변수 언제 사용해야하는가?

  • 모든 클래스별로, 공유되는 자원이 필요할때 사용한다. 예) Math.PI 그렇지 않은 경우 static을 사용하면 쓸데없이 메모리를 점유한다.
  • 전역변수로 동작하기 때문에, 추적이 어렵다, 불변을 원한다면, final을 통해 변하지 않도록 한다.

2) static 메서드 언제 사용해야하는가?

  • 인스턴스 멤버를 사용하지 않고, 클래스 변수와 파라미티러로 받은 값만 필요할때 사용한다.
    -> 예시) Math.toRadians
profile
callmeskye

0개의 댓글