'정적'키워드는 클래스에서 무엇을합니까?


444

구체적으로, 나는이 코드를 시도했다 :

package hello;

public class Hello {

    Clock clock = new Clock();

    public static void main(String args[]) {
        clock.sayTime();
    }
}

그러나 그것은 오류를 주었다

정적 메소드 main에서 비 정적 필드에 액세스 할 수 없음

그래서 나는 clock이것으로 선언을 바꿨다 .

static Clock clock = new Clock();

그리고 효과가있었습니다. 해당 키워드를 선언 전에 두는 것은 무엇을 의미합니까? 해당 객체에 수행 할 수있는 작업과 관련하여 정확히 무엇을하고 /하거나 제한합니까?


CLASSLOADER 당 클래스 당 하나의 정적 인스턴스가 있음을 다시 한 번 기억하십시오.
— Javamann

답변:


633

static 멤버는 특정 인스턴스 대신 클래스에 속합니다.

이는 클래스의 인스턴스를 백만 개 만들거나 만들지 않은 경우에도 하나의 static필드 인스턴스 만 존재 한다는 것을 의미 합니다 [1] . 모든 인스턴스가 공유합니다.

static메소드는 특정 인스턴스에 속하지 않기 때문에 인스턴스 멤버를 참조 할 수 없습니다. 주어진 예에서, main어떤 Hello클래스의 인스턴스 (따라서 Clock클래스의 인스턴스 )를 참조해야하는지 알 수 없습니다. static회원은 회원 만 참조 할 수 있습니다 static. 인스턴스 멤버는 물론 static멤버에 액세스 할 수 있습니다 .

참고 : 물론 static멤버 는 객체 참조를 통해 인스턴스 멤버에 액세스 할 수 있습니다 .

예:

public class Example {
    private static boolean staticField;
    private boolean instanceField;
    public static void main(String[] args) {
        // a static method can access static fields
        staticField = true;

        // a static method can access instance fields through an object reference
        Example instance = new Example();
        instance.instanceField = true;
    }

[1] : 런타임 특성에 따라 ClassLoader 또는 AppDomain 또는 스레드 당 하나 일 수 있지만 그 점이 아닙니다.


5
.NET에서는 [ThreadStatic] 속성을 사용하여이 동작을 수정할 수도 있습니다.이 속성은 정적을 특정 스레드에 대해 로컬로 만듭니다.
— TheSoftwareJedi

4
나는 이것이 오래된 게시물이라는 것을 알고 있지만 나와 같은 초보자에게는 이것이 도움이 될 수 있습니다. stackoverflow.com/questions/7026507/…
— user3526905

private var이므로 instance.instanceField에 액세스 할 수 없습니까? 또는 자체 클래스 내부의 객체를 인스턴스화했기 때문에 유효합니까? 나에게는 재귀적인 악몽처럼 들리지만 나는 자바 초보자입니다.
— Matt Corby

클래스의 정적 멤버가 2 개의 다른 스레드에서 참조되는 경우 해당 정적 멤버의 인스턴스는 몇 개입니까? 2 인 것 같지만 스레드간에 동일한 인스턴스를 원하면 volatile 키워드를 사용해야합니다. 그 맞습니까?
— Dan

.. 그리고 클래스의 인스턴스가 남아 있지 않으면 값이 유지됩니까?
— mckenzm

130

"Hello"클래스의 개별 인스턴스마다 하나씩이 아니라 Hello에 "clock"인스턴스가 하나만 있다는 의미입니다. 따라서 모든 인스턴스간에 공통적으로 공유되는 "clock"참조가 하나 있음을 의미합니다. "Hello"클래스

따라서 코드의 어느 곳에서나 "새 Hello"를 수행해야하는 경우 : 첫 번째 시나리오 ( "정적"을 사용하지 않고 변경 전)에서 "새 Hello"를 호출 할 때마다 새 시계가 만들어집니다. 그러나 두 번째 시나리오 ( "정적"을 사용한 변경 후)의 B-에서는 모든 "새 Hello"인스턴스가 여전히 처음 작성된 초기 및 동일한 "시계"참조를 공유하고 사용합니다.

메인 외부의 "시계"가 필요하지 않으면 다음과 같이 작동합니다.

package hello;
public class Hello
{
    public static void main(String args[])
    {
      Clock clock=new Clock();
      clock.sayTime();    
    }
}

이것이 가장 일반적인 방법입니다. main()루틴은 자체 포함해야한다.
— Jason S

1
두 번째 인스턴스에서는 메인 메소드가 호출 될 때마다 Clock의 새 인스턴스를 생성합니다.
— Upvote를 클릭하십시오

2
두 번째 인스턴스 인 clock static은 한 번만 생성합니다. 내 예에서 시계가 메인 내에 있으면 예, 메인이 호출 될 때마다 새로 만듭니다. 그러나 일반적으로 main은 프로그램 시작시 한 번만 호출되며 종료되면 모든 것이 해제됩니다.
— Paul Tomblin

주요 방법으로 새로운 시계를 만드는 것이 어떻게 가능합니까? 당신이 말한 것처럼 main이 호출 될 때마다 새로 작성되지만 main 메소드는 하나만 있습니다. 그 주요 방법이 다른 시계 인스턴스를 어떻게 참조 할 수 있습니까? 메인에서 새로운 시계 인스턴스를 만들고 sayTime () 메소드를 사용하는 방법을 이해하는 것은 조금 어렵지만, 인스턴스를 메인으로 만들고 sayTime ()을 사용하는 것은 불가능합니다. main이 한 번 호출되면 모든 것이 어떻게 무료입니까? @PaulTomblin
— ShakibaZar

@ user5621266 mainOP가했기 때문에이 방법 만 사용했습니다 . 대신 다른 곳에서 호출 된 공용 메서드이고 Hello 클래스가 두 번 이상 인스턴스화 된 경우 clock정적이 아닌 한 각 Hello 인스턴스에 대해 Clock 인스턴스를 만들 수 있습니다 .
— Paul Tomblin

97

static키워드 수단은 무엇인가 (필드, 방법 또는 중첩 클래스)하는 관계가 형식 이 아닌 특정 인스턴스의 유형. 예를 들어, 클래스의 Math.sin(...)인스턴스없이 호출 하면 Math클래스 의 인스턴스를 만들 수 없습니다Math .

자세한 정보는 관련 Oracle Java Tutorial 비트를 참조하십시오 .


사이드 노트

Java는 불행히도 정적 멤버가 인스턴스 멤버 인 것처럼 액세스 할 수 있습니다. 예 :

// Bad code!
Thread.currentThread().sleep(5000);
someOtherThread.sleep(5000);

즉, 만들어 보는 것처럼 sleep인스턴스 방법이지만, 실제로는 정적 방법입니다 - 그것은 항상 현재의 thread의 잠을 수 있습니다. 호출 코드에서이를 명확하게하는 것이 좋습니다.

// Clearer
Thread.sleep(5000);

1
또 다른 예 : System.out.println () 은 클래스 메서드처럼 보이지만 실제로는 인스턴스 메서드입니다. out은 System 클래스의 PrintStream 인스턴스이므로
— Jiahui Zhang

@LeslieCheung : 아니요, 나에게 System.out타입 이름이 아닌 클래스 메소드처럼 보이지 않습니다.
— Jon Skeet

42

staticJava 의 키워드는 변수 또는 함수가 실제 객체 자체가 아니라 유형에 속하는 해당 클래스의 모든 인스턴스간에 공유됨을 의미합니다 .

따라서 변수가 있고 한 인스턴스에서 변수 private static int i = 0;를 늘리면 ( i++) 모든 변경 사항이 모든 인스턴스에 반영됩니다. i이제 모든 인스턴스에서 1이됩니다.

정적 메소드는 객체를 인스턴스화하지 않고 사용할 수 있습니다.


4
"모든 인스턴스간에 공유"는 잘못된 인상을줍니다. IMO- 개체의 인스턴스 가 필요하다는 것을 나타냅니다.
— Jon Skeet

1
(반면에 정말있을 필요가 없습니다 모든 정적 필드 등등에 속하기 때문에, 인스턴스 유형 .)
— 존 소총

@Jon Skeet static은 객체가 아닌 유형에 속합니까? 더 자세하게 말할 수 있습니까? 데이터 유형과 같은 유형 : int, double, ...?
— truongnm

@truongnm : 변수 / 메소드를 선언하는 클래스에서와 같이 입력하십시오.
— Jon Skeet

26

정적 멤버의 기본 사용법 ...

public class Hello
{
    // value / method
    public static String staticValue;
    public String nonStaticValue;
}

class A
{
    Hello hello = new Hello();
    hello.staticValue = "abc";
    hello.nonStaticValue = "xyz";
}

class B
{
    Hello hello2 = new Hello(); // here staticValue = "abc"
    hello2.staticValue; // will have value of "abc"
    hello2.nonStaticValue; // will have value of null
}

이렇게하면 클래스 인스턴스 Hello를 다른 클래스로 보내지 않고 모든 클래스 멤버에서 값을 공유 할 수 있습니다. 정적 클래스는 클래스 인스턴스를 만들 필요가 없습니다.

Hello hello = new Hello();
hello.staticValue = "abc";

클래스 이름으로 정적 값이나 메소드를 호출 할 수 있습니다.

Hello.staticValue = "abc";

22

정적은 클래스와 연결된 메서드 나 변수를 사용하기 위해 클래스의 인스턴스를 만들 필요가 없음을 의미합니다. 귀하의 예에서 다음을 호출 할 수 있습니다.

Hello.main(new String[]()) //main(...) is declared as a static function in the Hello class

직접 대신 :

Hello h = new Hello();
h.main(new String[]()); //main(...) is a non-static function linked with the "h" variable

정적 메서드 (클래스에 속함) 내에서는 정적이 아닌 멤버에 액세스 할 수 없습니다. 값은 클래스의 인스턴스화에 따라 달라지기 때문입니다. 인스턴스 멤버 인 비 정적 Clock 객체는 Hello 클래스의 각 인스턴스에 대해 다른 값 / 참조를 가지므로 클래스의 정적 부분에서 액세스 할 수 없습니다.


정적 컨텍스트에 대한 훌륭한 설명 :)
— Abdel-Raouf

20

자바 정적 :

정적은 비 액세스 수정 자입니다. 정적 키워드는 클래스의 인스턴스보다 클래스에 속합니다. 변수 또는 메소드를 클래스에 첨부하는 데 사용할 수 있습니다.

정적 키워드는 다음과 함께 사용할 수 있습니다.

방법

변하기 쉬운

다른 클래스 내에 중첩 된 클래스

초기화 블록

다음과 함께 사용할 수 없습니다 :

클래스 (중첩되지 않음)

건설자

인터페이스

메서드 로컬 내부 클래스 (차이와 중첩 클래스)

내부 클래스 메소드

인스턴스 변수

지역 변수

예:

생성자에서 증가한 count라는 인스턴스 변수 가있는 다음 예제를 상상해보십시오 .

package pkg;

class StaticExample {
    int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

산출:

1 1 1

인스턴스 변수는 객체 생성시 메모리를 가져 오므로 각 객체는 인스턴스 변수의 복사본을 갖게되며, 증가하면 다른 객체에는 반영되지 않습니다.

이제 인스턴스 변수 수를 정적 변수 수로 변경 하면 프로그램에서 다른 출력을 생성합니다.

package pkg;

class StaticExample {
    static int count = 0;// will get memory when instance is created

    StaticExample() {
        count++;
        System.out.println(count);
    }

    public static void main(String args[]) {

        StaticExample c1 = new StaticExample();
        StaticExample c2 = new StaticExample();
        StaticExample c3 = new StaticExample();

    }
}

산출:

1 2 3

이 경우 정적 변수는 메모리를 한 번만 가져옵니다. 객체가 정적 변수의 값을 변경하면 해당 값을 유지합니다.

최종 정적 :

final 및 static으로 선언 된 전역 변수 는 전체 실행에서 변경되지 않은 상태로 유지됩니다. 정적 멤버는 클래스 메모리에 저장되며 전체 실행에서 한 번만로드되기 때문입니다. 클래스의 모든 객체에 공통입니다. 정적 변수를 final로 선언하면 모든 객체가 최종 값을 변경할 수 없습니다. 따라서 final 및 static으로 선언 된 변수를 상수라고도합니다. 인터페이스의 모든 필드는 기본적으로 최종적이고 정적이므로 상수라고합니다.

여기에 이미지 설명을 입력하십시오

사진 자료 : 최종 정적


15

기존 답변에 추가하려면 그림으로 시도해 보겠습니다.

2 %의 이율이 모든 저축 계좌에 적용됩니다. 따라서 정적 입니다.

잔액은 개별적 이어야 하므로 정적 이 아닙니다 .

여기에 이미지 설명을 입력하십시오


13

이 논의에서는 지금까지 클래스 로더 고려 사항을 무시했습니다. 엄밀히 말하면 Java 정적 필드는 주어진 클래스 로더 에 대한 클래스의 모든 인스턴스간에 공유 됩니다.


1
이것은 Merhdad의 답변에 대한 의견에서 Apocalisp가 언급했습니다.
— Zach Langley

1
좋은 지적. 많은 사람들이 이것을 알지 못하지만 일단 클래스 로더를 망치기 시작하면 매우 중요합니다.
— sleske

2
이것은 모두 사실이지만 질문에 대답하지 않습니다. 주석으로 게시되어 있어야합니다.
— Lorne의 후작

7

필드는 클래스 또는 클래스의 인스턴스에 할당 될 수 있습니다. 기본적으로 필드는 인스턴스 변수입니다. static필드 를 사용 하면 클래스 변수가되므로 하나만 clock있습니다. 한 곳에서 변경하면 어디에서나 볼 수 있습니다. 인스턴스 변수는 서로 독립적으로 변경됩니다.


6

키워드 static는 인스턴스가 아닌 클래스 자체에 속하는 필드 또는 메소드를 나타내는 데 사용됩니다. 코드를 사용하여 객체 Clock가 정적 인 경우 Hello클래스 의 모든 인스턴스는 이 Clock데이터 멤버 (필드)를 공통으로 공유합니다. 정적이 아닌 경우 각 개별 인스턴스 Hello는 고유 Clock필드를 가질 수 있습니다 .

문제는 코드를 실행할 수 있도록 클래스에 기본 메소드를 추가 Hello했다는 것입니다. 여기서 문제는 주요 메소드가 정적이므로 비 정적 필드 또는 그 내부의 메소드를 참조 할 수 없다는 것입니다. 두 가지 방법으로이 문제를 해결할 수 있습니다.

  1. 기본 메소드 Hello내에서 참조 될 수 있도록 클래스 의 모든 필드와 메소드를 정적 으로 작성하십시오 . 이것은 실제로 좋은 일이 아닙니다 (또는 잘못된 이유는 필드 및 / 또는 메소드를 정적으로 만듭니다)
  2. Hello기본 메소드 내에 클래스 의 인스턴스를 작성 하고 처음에 의도 한 방식으로 모든 필드 및 메소드에 액세스하십시오.

당신에게 이것은 다음과 같은 코드 변경을 의미합니다.

package hello;

public class Hello {

    private Clock clock = new Clock();

    public Clock getClock() {
        return clock;
    }

    public static void main(String args[]) {
        Hello hello = new Hello();
        hello.getClock().sayTime();
    }
}

6

Java에서 static키워드는 단순히 다음을 나타내는 것으로 간주 될 수 있습니다.

"특정 사례와 관련이 있거나 관계가없는 경우"

static이런 식으로 생각 하면 다양한 상황에서 그 사용법을 이해하기가 더 쉬워집니다.

  • static필드 오히려 특정 인스턴스보다는 클래스에 속하는 필드

  • static방법은 전혀 개념이없는 방법이다 this; 클래스에 정의되어 있으며 참조가 전달되지 않는 한 해당 클래스의 특정 인스턴스에 대해 알지 못합니다.

  • static(클로징 클래스의 인스턴스에 대한 참조가 전달 된 경우 제외) 멤버 클래스는 둘러싸는 클래스의 인스턴스의 개념이나 지식없이 중첩 된 클래스


5

Static은 시계 멤버를 인스턴스 멤버 대신 클래스 멤버로 만듭니다. 정적 키워드가 없으면 Hello 클래스 (클럭 멤버 변수가있는)의 인스턴스를 만들어야합니다. 예 :

Hello hello = new Hello();
hello.clock.sayTime();


5

나는 "helper"클래스에서 정적 메소드 (가능한 경우에만)를 좋아하는 것을 개발했다.

호출 클래스는 도우미 클래스의 다른 멤버 (인스턴스) 변수를 만들 필요가 없습니다. 헬퍼 클래스의 메소드를 호출하기 만하면됩니다. 또한 더 이상 생성자가 필요없고 멤버 (인스턴스) 변수가 필요하지 않기 때문에 도우미 클래스가 향상되었습니다.

아마도 다른 장점이있을 것입니다.


4
//Here is an example 

public class StaticClass 
{
    static int version;
    public void printVersion() {
         System.out.println(version);
    }
}

public class MainClass 
{
    public static void main(String args[]) {  
        StaticClass staticVar1 = new StaticClass();
        staticVar1.version = 10;
        staticVar1.printVersion() // Output 10

        StaticClass staticVar2 = new StaticClass();
        staticVar2.printVersion() // Output 10
        staticVar2.version = 20;
        staticVar2.printVersion() // Output 20
        staticVar1.printVersion() // Output 20
    }
}

3

정적 멤버에 "this"포인터가없는 것으로 생각할 수도 있습니다. 모든 인스턴스간에 공유됩니다.


3

정적 개념 이해

public class StaticPractise1 {
    public static void main(String[] args) {
        StaticPractise2 staticPractise2 = new StaticPractise2();
        staticPractise2.printUddhav(); //true
        StaticPractise2.printUddhav(); /* false, because printUddhav() is although inside StaticPractise2, but it is where exactly depends on PC program counter on runtime. */

        StaticPractise2.printUddhavsStatic1(); //true
        staticPractise2.printUddhavsStatic1(); /*false, because, when staticPractise2 is blueprinted, it tracks everything other than static  things and it organizes in its own heap. So, class static methods, object can't reference */

    }
}

이급

public class StaticPractise2 {
    public static void printUddhavsStatic1() {
        System.out.println("Uddhav");
    }

    public void printUddhav() {
        System.out.println("Uddhav");
    }
}

2

main() 두 가지 기본 제한 사항이있는 정적 메소드입니다.

  1. 정적 메소드는 비 정적 데이터 멤버를 사용하거나 비 정적 메소드를 직접 호출 할 수 없습니다.
  2. this()그리고 super()정적 컨텍스트에서 사용할 수 없습니다.

    class A {  
        int a = 40; //non static
        public static void main(String args[]) {  
            System.out.println(a);  
        }  
    }

출력 : 컴파일 시간 오류


1

정적 변수 정적 메소드에서만 액세스 할 수 있으므로 정적 변수를 선언하면 해당 getter 및 setter 메소드가 정적 메소드가됩니다.

정적 메소드는 클래스 이름을 사용하여 액세스 할 수있는 클래스 레벨입니다.

다음은 정적 변수 Getter 및 Setter의 예입니다.

public class Static 
{

    private static String owner;
    private static int rent;
    private String car;
    public String getCar() {
        return car;
    }
    public void setCar(String car) {
        this.car = car;
    }
    public static int getRent() {
        return rent;
    }
    public static void setRent(int rent) {
        Static.rent = rent;
    }
    public static String getOwner() {
        return owner;
    }

    public static void setOwner(String owner) {
        Static.owner = owner;
    }

}

1

이 개념에 대한 '정적'이라는 단어의 선택에 대한 질문이 여기 에 제기되었습니다 . 이 질문에 대한 답을 얻지 못했지만 어원이 명확하게 해결되지 않았다고 생각합니다. 그래서...


C로 시작하는 키워드 재사용 때문입니다.

함수 본문 내에서 C로 데이터 선언을 고려하십시오.

    void f() {
        int foo = 1;
        static int bar = 2;
         :
    }

변수 foo는 함수가 입력 될 때 스택에 작성되며 함수가 종료되면 제거됩니다. 반대로 바는 항상 존재하므로 일반적인 영어 의미에서 '정적'입니다. 어디로도 가지 않습니다.

Java 및 유사한 언어는 동일한 데이터 개념을 갖습니다. 데이터는 클래스의 인스턴스 당 (객체 당) 또는 전체 클래스에 대해 한 번 할당 될 수 있습니다. Java는 C / C ++ 프로그래머에게 친숙한 구문을 목표로하기 때문에 'static'키워드가 적합합니다.

    class C {
        int foo = 1;
        static int bar = 2;
         :
    }

마지막으로, 우리는 방법에옵니다.

    class C {
        int foo() { ... }
        static int bar() { ... }
         :
    }

개념적으로 말하자면 C 클래스의 모든 인스턴스에 대해 foo () 인스턴스가 있습니다. 전체 C 클래스에 대해 bar () 인스턴스는 하나뿐입니다. 이는 데이터에 대해 논의한 사례와 유사하므로 'static '는 언어에 예약 된 키워드를 더 추가하지 않으려는 경우 합리적인 선택입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.