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


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.