처음부터 차근차근

[Java] static 본문

Language/Java

[Java] static

HangJu_95 2023. 12. 29. 19:03
728x90

Static이란?

정적(static)은 고정된이란 의미를 가지고 있습니다. Static이라는 키워드를 사용하여 Static변수와 Static메소드를 만들 수 있는데 다른말로 정적필드와 정적 메소드라고도 하며 이 둘을 합쳐 정적 멤버라고 합니다.(클래스 멤버라고도 합니다.) 정적 필드와 정적 메소드 객체(인스턴스)에 소속된 멤버가 아니라 클래스에 고정된 멤버입니다. 그렇기에 클래스 로더가 클래스를 로딩해서 메소드 메모리 영역에 적재할때 클래스별로 관리됩니다. 따라서 클래스의 로딩이 끝나는 즉시 바로 사용할 수 있습니다.

Static 멤버 생성

https://coding-factory.tistory.com/524

Static 키워드를 통해 생성된 정적멤버들은 Heap영역이 아닌 Static영역에 할당됩니다. Static 영역에 할당된 메모리는 모든 객체가 공유하여 하나의 멤버를 어디서든지 참조할 수 있는 장점을 가지지만 Garbage Collector의 관리 영역 밖에 존재하기에 Static영역에 있는 멤버들은 프로그램의 종료시까지 메모리가 할당된 채로 존재하게 됩니다. 그렇기에 Static을 너무 남발하게 되면 만들고자 하는 시스템 성능악영향을 줄 수 있습니다.

Static 변수

Static을 변수에 적용하여 정적 필드를 만들어보겠습니다.

package static1;

public class Data3 {
    public String name;
    public static int count; // static

    public Data3(String name) {
        this.name = name;
        count++;
//        Data3.count++; // 이것도 가능. 붕어빵 틀에 접근하는 것이니깐.
    }
}
  • 기존 코드를 유지하기 위해 새로운 클래스 Data3 을 만들었다.
  • 이렇게 멤버 변수에 static 을 붙이게 되면 static변수, 정적 변수 또는 클래스 변수라 한다.
  • 객체가 생성되면 생성자에서 정적 변수 count의 값을 하나 증가시킨다.
  • static int count 부분을 보자. 변수 타입(int) 앞에 static 키워드가 붙어있다.
package static1;

public class DataCountMain3 {
    public static void main(String[] args) {
        Data3 data1 = new Data3("A");
        System.out.println("A count = " + Data3.count);

        Data3 data2 = new Data3("B");
        System.out.println("B count = " + Data3.count);

        Data3 data3 = new Data3("C");
        System.out.println("C count = " + Data3.count);

        Data3 data4 = new Data3("D");
        // 인스턴스를 통한 접근
        System.out.println(data4.count);

        // 클래스를 통한 접근
        System.out.println(Data3.count);
    }
}

코드를 보면 접근하는 방법이 조금 특이한데 클래스에 직접 접근하는 것 처럼 느껴집니다.

정적 변수 접근

멤버 변수(필드)의 종류

  • 인스턴스 변수 : static이 붙지 않은 멤버 변수
    • static이 붙지 않은 멤버 변수는 인스턴스를 생성해야 사용할 수 있고, 인스턴스에 소속되어 있다.
    • 인스턴스 변수는 인스턴스를 만들 때 마다 새로 만들어진다
  • 클래스 변수 static이 붙은 멤버 변수
    • 클래스 변수, 정적 변수, static 변수 등으로 부릅니다.
    • static이 붙은 멤버 변수는 인스턴스와 무관하게 클래스에 바로 접근해서 사용할 수 있고, 클래스 자체에 소속되어 있습니다. 따라서 클래스 변수라 합니다.
    • 클래스 변수는 자바 프로그램을 시작할 때 딱 1개가 만들어집니다. 인스턴스와는 다르게 보통 여러곳에서 공유하는 목적으로 사용됩니다.

변수와 생명 주기

  • 지역 변수(매개변수 포함) : 지역 변수는 스택 영역에 있는 스택 프레임 안에 보관된다. 메서드가 종료되면 스택 프레임도 제거 되는데 이때 해당 스택 프레임에 포함된 지역 변수도 함께 제거된다. 따라서 지역 변수는 생존 주기가 짧다.
  • 인스턴스 변수 : 인스턴스에 있는 멤버 변수를 인스턴스 변수라 한다. 인스턴스 변수는 힙 영역을 사용한다. 힙 영역은 GC(가비지 컬렉션)가 발생하기 전까지는 생존하기 때문에 보통 지역 변수보다 생존 주기가 길다.
  • 클래스 변수 : 클래스 변수는 메서드 영역의 static 영역에 보관되는 변수이다. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간이다. 클래스 변수는 해당 클래스가 JVM에 로딩 되는 순간 생성된다. 그리고 JVM이 종료될 때 까지 생명주기가 어어진다. 따라서 가장 긴 생명주기를 가진다.

정적 변수 접근 법

//추가
//인스턴스를 통한 접근
Data3 data4 = new Data3("D");
System.out.println(data4.count);
//클래스를 통합 접근
System.out.println(Data3.count);

static 변수는 클래스를 통해 바로 접근할 수도 있고, 인스턴스를 통해서 접근할 수도 있습니다.

그러나 정적 변수의 경우 인스턴스를 통한 접근은 추천하지 않습니다. 코드를 읽을 때 마치 인스턴스 변수에 접근하는 것 처럼 오해할 수도 있기 때문에 정적 변수에 접근할 때는 클래스를 통해서 접근해야 합니다.

Static 메서드

간단한 예시를 통해 static 메서드도 알아보겠습니다.

package static2;

public class DecoUtil2 {
    public static String deco(String str) {
        String result = "*" + str + "*";
        return result;
    }
}
package static2;

public class DecoMain2 {
    public static void main(String[] args) {
        String s = "Hello Java";
        String deco = DecoUtil2.deco(s);

        System.out.println("before: " + s);
        System.out.println("after: " + deco);
    }
}

정적 메서드를 통해 정적 변수처럼 인스턴스 생성 없이 클래스 명을 통해서 메서드를 바로 호출할 수 있습니다.

  • 클래스 메서드(정적 메서드) :정적 메서드라는 용어는바로 호출하는 것 처럼 느껴지기 때문이다. static 이 정적이라는 뜻이기 때문이고, 클래스 메서드라는 용어는 인스턴스 생성 없이 마치 클래스에 있는 메서드를 바로 호출하는 것 처럼 느껴지기 때문이다.
  • 인스턴스 메서드 : static이 붙지 않은 메서드는 인스턴스를 생성해야 호출할 수 있다. 이것을 인스턴스 메서드라 한다.

정적 메서드 사용법

  • static 메서드는 static 만 사용할 수 있다.
    • 클래스 내부의 기능을 사용할 때, 정적 메서드는 static 이 붙은 정적 메서드나 정적 변수만 사용할 수 있다.
    • 클래스 내부의 기능을 사용할 때, 정적 메서드는 인스턴스 변수나, 인스턴스 메서드를 사용할 수 없다.
  • 반대로 모든 곳에서 static 을 호출할 수 있다.
    • 정적 메서드는 공용 기능이다. 따라서 접근 제어자만 허락한다면 클래스를 통해 모든 곳에서 static 을 호출할 수 있다.
package static2;

public class DecoData {
    private int instanceValue;
    private static int staticValue;

    public static void staticCall() {
//        instanceValue++; // 인스턴스 변수 접근, 컴파일러 에러
//        instanceMethod(); // 인스턴스 메서드 접근, 컴파일 에러

        staticValue++; // 정적 변수 접근
        staticMethod(); //
    }

    // 객체의 참조값을 직접 매개변수로 전달하면 정적 메서드도 인스턴스의 변수나 메서드를 호출할 수 있다.
    public static void staticCall(DecoData data) {
        data.instanceValue++;
        data.instanceMethod();
    }

    public void instanceCall() {
        instanceValue++; // 인스턴스 변수 접근, 컴파일러 에러
        instanceMethod(); // 인스턴스 메서드 접근, 컴파일 에러

        staticValue++;
        staticMethod();
    }

    private void instanceMethod() {
        System.out.println("instanceValue= " + instanceValue);
    }
    private static void staticMethod() {
        System.out.println("staticValue= " + staticValue);
    }
}
package static2;

public class DecoDataMain {
    public static void main(String[] args) {
        System.out.println("1.정적 호출");
        DecoData.staticCall();

        System.out.println("2.인스턴스 호출1");
        DecoData data1 = new DecoData();
        data1.instanceCall();

        System.out.println("3.인스턴스 호출2");
        DecoData data2 = new DecoData();
        data2.instanceCall();
    }
}

정적 메서드가 인스턴스의 기능을 사용할 수 없는 이유

정적 메서드는 클래스의 이름을 통해 바로 호출할 수 있습니다. 그래서 인스턴스처럼 참조값의 개념이 없습니다.

특정 인스턴스의 기능을 사용하려면 참조값을 알아야 하는데, 정적 메서드는 참조값 없이 호출하며, 따라서 정적 메서드 내부에서 인스턴스 변수나 인스턴스 메서드를 사용할 수 없습니다.

단, 객체의 참조값을 직접 매개변수로 전달하면 정적 메서드도 인스턴스의 변수나 메서드에서 호출 가능합니다.

정적 메서드 활용

  • 객체 생성이 필요 없이 메서드의 호출만으로 필요한 기능을 수행할 때 주로 사용
  • 간단한 메서드 하나로 끝나는 유틸리티성 메서드에 자주 사용

정적 메서드 접근 법

static 메서드는 static 변수와 마찬가지로 클래스를 통해 바로 접근할 수 있고, 인스턴스를 통해서도 접근할 수 있으나, 클래스를 통해 접근하는 것이 더 명확하기 때문에 클래스로 접근합니다.

static import

정적 메서드를 사용할 때 해당 메서드를 다음과 같이 자주 호출해야 한다면 static import 기능을 사용할 수 있습니다.

package static2;

//import static static2.DecoData.staticCall; // 특정 클래스 메서드 하나만 사용할 경우
import static static2.DecoData.*; // 특정 클래스 메서드를 전부 사용하고 싶은 경우
public class DecoDataMain2 {
    public static void main(String[] args) {
        System.out.println("1.정적 호출");
        staticCall();
        staticCall();
        staticCall();
        staticCall();

        System.out.println("2.인스턴스 호출1");
        DecoData data1 = new DecoData();
        data1.instanceCall();

        System.out.println("3.인스턴스 호출2");
        DecoData data2 = new DecoData();
        data2.instanceCall();

    }
}

참조

 

[Java] 자바 static의 의미와 사용법

정적(Static)이란? 정적(static)은 고정된이란 의미를 가지고 있습니다. Static이라는 키워드를 사용하여 Static변수와 Static메소드를 만들 수 있는데 다른말로 정적필드와 정적 메소드라고도 하며 이

coding-factory.tistory.com

 

김영한의 실전 자바 - 기본편 강의 - 인프런

실무에 필요한 자바 객체 지향의 핵심 개념을 예제 코드를 통해 쉽게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문법을 안다

www.inflearn.com

 

'Language > Java' 카테고리의 다른 글

[Java] 다형성  (0) 2024.01.01
[Java] final  (1) 2023.12.31
[Java] Java 메모리 구조  (1) 2023.12.29
[Java] 제어자, 접근 제어자  (0) 2023.12.26
[Java] Package  (1) 2023.12.26