정적 키워드 이해


16

Java, Javascript 및 PHP를 사용한 개발 경험이 있습니다.

Microsoft Visual C # 2010을 단계별로 읽고 있는데 C # 언어를 소개하는 데 매우 유용한 책이라고 생각합니다.

정적 키워드를 이해하는 데 문제가있는 것 같습니다. 클래스가 정적으로 선언되면 내가 이해하는 것부터 모든 메소드와 변수는 정적이어야합니다. main 메소드는 항상 정적 메소드이므로 main 메소드가 존재하는 클래스에서는 main 메소드에서 모든 변수와 메소드를 정적로 선언해야합니다. 또한 다른 클래스에서 정적 메서드를 호출하기 위해 클래스 이름을 사용할 수있는 객체를 만들 필요가 없다는 것을 알았습니다.

그러나 정적 키워드의 실제 목적은 무엇입니까? 정적 변수와 메소드는 언제 선언해야합니까?


4
C #의 static은 Java의 static과 거의 동일합니다. Java로 이해한다면 C #에서 아무런 문제가 없어야합니다.
superM

Java는 저의 첫 프로그래밍 언어였으며이 개념을 이해하지 못했습니다. 저는 짧은 시간 동안 Java 만 사용했습니다
Nistor Alexandru

간단히 말해서 : 객체 지향이 필요하지 않은 경우 (예 : 일부 독립형 메소드 또는 변수) "정적"을 사용하십시오. 클래스를 정적이라고 선언한다는 것은 객체가 아닌 객체 지향 함수와 변수를 공통 이름 (공백) 인 클래스 이름에 넣는 것을 의미합니다.
Doc Brown

답변:


15

C #의 '정적'키워드는 클래스의 모든 인스턴스간에 공유되는 클래스 또는 클래스 자체를 나타냅니다. 예를 들어 정적으로 표시된 필드는 클래스 이름을 통해 해당 클래스의 모든 인스턴스에서 액세스 할 수 있습니다.

public class SomeObject
{
    //Static Field
    static int Foo = 3;

    //instance field
    private int _Foo2 = 4;

    //instance property
    public int Foo2{get{return _Foo2;}set{_Foo2 = value;}}


    //static factory method
    public static SomeObject CreateSomeObject(int fooValue)
    {
        SomeObject retVal = new SomeObject();
        retVal.Foo2 = fooValue;
        return retVal;
    }

    //Parameterless instance constructor
    public SomeObject()
    {
    }

    public static int Add(int x)
    {
        //Static methods can only deal with local variables, or fields that
        //  are also static in the class.  This one adds x to the static member foo
        return x + Foo;

        //Foo2 is not accessable here!
    }

      //Instance method
    public int AddSomething(int x)
    {
        //Add x to the property value of Foo2
        return x + this.Foo2;

        //Note that Foo *is* accessable here as 'SomeObject.Foo'
    }

}

나는 확장 메소드를 만드는 것을 제외하고 정적으로 표시된 클래스를 사용한 적이 없다고 솔직히 말할 수 있습니다 ( 확장 메소드에 대한 빠른 자습서 ).

어쨌든 팩토리 패턴싱글 톤 패턴 과 같은 정적 메소드를 사용하기위한 특정 디자인 패턴이 있지만 기억해야 할 중요한 점은 정적 메소드 및 생성자가 클래스의 특정 인스턴스를 처리하지 않는다는 것입니다. 일반적으로 계산을 수행하거나 객체를 비교합니다. 참조하는 "Main"메소드는 항상 정적이지만 다른 관점에서 보려면 이 기사를 참조하십시오 .

이를 위해 정적 메소드와 인스턴스화 메소드, 필드 및 특성의 차이점을 호출하는 방법이 있습니다.

public static void Main(string[] args)
{
    //This is a static method that starts a thread in an application
    // space.  At this point not everything actually has to be static...

    //Here is an instantiation with a parameterless contruction
    SomeObject obj = new SomeObject();

    //Here is an instantiation using a static factory method
    SomeObject obj2 = SomeObject.CreateSomeObject(3);

    //Getting field value from static field
    // Notice that this references the class name, not an instance
    int fooValue1 = SomeObject.Foo;

    //Getting property value from instance
    //  Note that this references an object instance
    int fooValue2 = obj2.Foo2;

    //Instance method must be called through an object
    obj2.AddSomething(4);  //if default constructor, would return 8

    //Static methods must be called through class name
    SomeObject.Add(4); //Returns 7
}

또한 정적 클래스에 대한 자세한 내용은 이 게시물 을 확인하십시오 .


18

여기에 Joshua Bloch가 설명하는 방법이 있습니다. 이것은 메모리에서 인용됩니다.

클래스가 주택의 청사진과 동등하다고 상상해보십시오. 그런 다음, 수업의 실례가 수업을위한 것이므로 집이 설계도에 있다고 상상해보십시오. 하나의 클래스 (청색 인쇄)와 여러 개의 인스턴스 (하우스)를 만들 수 있습니다.

이제 상식에 따르면 주택 (인스턴스)이 설계도에 선언되어 있어도 할 수있는 대부분의 기능 / 행동은 실제 주택 (인스턴스)이 파란색으로 만들어 질 때까지 사용할 수 없습니다. -print (클래스). 예를 들어, 청사진에는 전등 스위치와 전구가 들어가야하는 장소가 들어있을 수 있지만, 청사진을 만들 수있는 방법이 없으므로 실제로 집을 지어야합니다. 전등 스위치를 켜고 끄고 특정 전구를 켜거나 끄려면.

그러나 블루 프린트에 직접 적용 할 수 있고 블루 프린트에서 실제 집을 만들지 않고도 블루 프린트에서 직접 사용 / 액세스 할 수있는 동작이있을 수 있습니다. 블루 프린트에 버튼을 누르면 해당 블루 프린트에 포함 된 집의 발자국이 표시됩니다 (벽의 모든 길이 등을 계산하여). 분명히 집을 먼저 짓고 발자국을 측정하는 것이 좋습니다. 그러나 블루 프린트만으로도이 작업을 수행 할 수 있으므로이 프린트를 블루 프린트로 구현하는 것이 더 도움이됩니다. 집의 발자국을 계산하는 블루 프린트 내장 버튼은 클래스에서 정적 기능을 갖는 것과 같습니다.


또는 Blueprint청사진으로 표현 된 집의 발자국을 계산하는 기능을 포함하여 청사진의 기능을 구현 하는 클래스 가 있습니다 . 그런 다음이 블루 프린트 인스턴스는 Builder(그 자체로 인스턴스 일 가능성이 있음)에게 공급되며,이 인스턴스는 블루 프린트를 Building기반으로 잠재적으로 임의의 수의 인스턴스 를 구성하고 출력하는 데 필요한 작업을 수행 합니다.
CVn

12

이 방법으로 보면 도움이됩니다.

  • 모든 유형에는 정적 인스턴스가 있습니다.
  • 정적 인스턴스는 정적 인스턴스를 통해 또는 다른 인스턴스를 작성하여 유형에 처음 액세스 할 때 작성됩니다.
  • 비 정적 인스턴스는 원하는 수만큼 만들 수 있지만 정적 인스턴스는 하나뿐입니다.
  • static으로 선언 된 클래스 내의 모든 것은 정적 인스턴스에 속하므로 사용자가 만든 다른 인스턴스에 액세스 할 수 없습니다. 그러나 다른 인스턴스는 정적 인스턴스에 액세스 할 수 있습니다.
  • 클래스가 static으로 선언되면 다른 인스턴스를 만들 수 없으며 정적 인스턴스 만 존재할 수 있습니다.
  • 일반 인스턴스의 생성자와 마찬가지로 정적 인스턴스의 정적 생성자를 선언 할 수 있습니다 (그러나 정적 선언).

정적 키워드를 사용하는 경우 :

  • 로컬 속성에 액세스 할 필요가없는 모든 메서드는 정적으로 선언 될 수 있습니다.
  • 어떤 상태도 가지고 있지 않고 (어쨌든 드 물어야 할) 도우미 클래스는 정적으로 선언 될 수 있습니다. 그들이해야할지는 또 다른 문제이다. 이 기능은 드물게 사용하십시오.
  • 클래스의 모든 인스턴스가 액세스해야하는 속성 및 필드는 정적으로 선언되어야합니다. 그러나 다른 옵션이없는 경우에만 사용하십시오.

+1, 요약하면 모든 유형에 정적 인스턴스가 1 개 있다는 사실을 알지 못했고 진실을 말하는 것이 이상하다고 생각합니다.
NoChance

2
@EmmadKareem 그것은 pdr이 사용하는 정신 모델 일뿐 "Looking at it this way helps"입니다. 당신은 그것이 사실이 아니기 때문에 이상하다고 생각하지만, 원한다면 그렇게 생각할 수 있습니다. 보어 모델을 알고 있습니까? 그것은 원자와 전자가 서로 상호 작용하는 법칙과 아이디어를 제시합니다. 모델은 당신이 무엇에 따라 작동하지만, 현실이 아니다.
phant0m 2018 년

@ phant0m, 설명 주셔서 감사합니다, 나는 그것이 모델이 아니라는 인상을 받았으며 그 때문에 놀랐습니다.
NoChance

실제로는 때로는 static로컬 속성을 사용하지 않기 때문에 메소드를 만들고 싶지 않은 이유 가 있습니다. 만들기 가지 static가 직접 클래스를 해결해야하기 때문에 고객에게 커플 링을 추가 할 수 있습니다. 예를 들어, 이것은 조롱으로 단위 테스트를 더 어렵게 만들 수 있습니다.
Allan

@Allan : 논란의 여지가 있지만, 클래스의 인스턴스 상태에 영향을 미치지 않는 클래스에서 퍼블릭 메서드를 호출하는 경우 클라이언트 개발자에게 명확하게 알리기 위해 정적이어야합니다. 이 방법으로 조롱이 필요한 경우, 여러 가지 다른 방법으로 해결할 수있는 다른 문제입니다.
pdr

4

가장 간단한 설명 --- 정적 => 환경 당 하나의 사본 만 존재합니다.

따라서 VM 또는 CLR에는 정적 클래스의 사본이 하나만 있으며 참조하는 다른 클래스는 해당 클래스를 참조하는 다른 모든 클래스와 메소드 및 데이터를 공유해야합니다.

정적 변수의 경우, 정적 변수를 참조 할 때 소유 클래스의 사본 수에 관계없이 모두 동일한 스토리지를 참조하는 런타임 환경에는이 변수의 인스턴스가 하나만 있습니다.


2

정적 멤버는 해당 클래스의 인스턴스가 아닌 클래스와 연결됩니다.

.Net에 대해 이야기하고 있으므로 String 클래스, 특히 SplitJoin 메서드를 고려하십시오 .

Split은 인스턴스 메소드입니다. 문자열 변수를 만들고 값을 지정하면 해당 변수 / 값에서 Split ()을 호출하고 "비트"배열을 가져올 수 있습니다.

String s1 = "abc,def,ghi" ; 
String[] array2 = s1.Split( ',' ) ; 

예를 들어, 메소드의 경우 주어진 클래스 인스턴스 내에 보유 된 값이 중요 합니다.

조인은 정적 메서드입니다. OK, 그것은 문자열 산출 결과 에 씹을 구분하고 문자열 배열의 지정된 때 문자열 클래스 "함께 할 수있는 뭔가가"그래서 있지만 것 없는 특정과 관련된 참으로, 인스턴스 값은 (모든 문자열 인스턴스 정적 메소드에는 사용할 수 없습니다).
다른 언어에서는 Join 메소드가 Array 클래스 (또는 아마도 StringArray 클래스)에 "고착"되었을 수도 있지만 Redmond의 친구는 String 클래스와 더 관련이 있다고 판단하여 거기에 넣었습니다. .

String[] array3 = { ... } 
s1 = String.Join( array3, "," ) ; 

또 다른 대안은 인스턴스 Join 메소드 를 갖는 것일 수 있습니다 . 여기서 String [클래스 인스턴스] 내에서 보유한 값은 결합 분리 문자로 사용되었습니다.

// Maybe one day ... 
String s4 = "," ; 
s1 = s4.Join( array3 ) ; 

2

static초보자가 이해하기위한 키워드는 조금 어려울 수 있습니다. 기본 목적은 클래스 멤버가 클래스의 단일 인스턴스에 속하지 않고 클래스 자체에 속하는 것으로 식별하는 것입니다.

너무 자세하게 설명하지 않고 C # (및 Java)은 모든 코드와 데이터가 객체에 속해야하므로 범위, 가시성 및 수명이 제한적이라는 객체 지향적 이상을 엄격하게 시행합니다. 일반적으로 실제 사물을 나타내는 객체의 기본 교리가 적용될 때마다 모범 사례입니다. 그러나 항상 그런 것은 아닙니다. 때로는 필요한 것은 코드를 포함하는 객체에 대한 참조를 전달하지 않고도 코드의 어느 곳에서나 얻을 수있는 함수 또는 변수이며 ,보고 있거나 변경하는 데이터가 모든 사람에게 정확히 맞는다는 보장 다른 것은 객체의 다른 인스턴스에 속하는 사본이 아니라 처리하는 것입니다.

이러한 동작은 "전역"함수 또는 변수의 형태로 C 및 C ++에서 사용 가능했으며 개체에 캡슐화되지 않았습니다. 따라서 C #과 Java는 타협으로 부모 개체가없고 범위가 제한된 인스턴스 멤버가없는 진정한 전역 코드의 중간 지점 인 "정적 범위"를 지원합니다.

로 선언 된 "코드 멤버"(함수, 속성, 필드)는 static프로그램 main()함수 의 첫 번째 줄에서 범위에 포함되며 main()함수가 종료 될 때까지 그대로 두지 않습니다 . 일반 영어로, 정적 멤버가 존재하며 프로그램이 실행되는 한 사용할 수 있습니다. 또한 정적 멤버는 해당 유형의 한 인스턴스 멤버가 아닌 유형 자체의 멤버로 호출하여 호출됩니다.

public class Foo
{
   public int MyInt {get;set;} //this is an "instance member"
   public static int MyStaticInt {get;set;} //this is a "static member"
}

...

var myFoo = new Foo();
myFoo.MyInt = 5; //valid
myFoo.MyStaticInt = 5; //invalid; MyStaticInt doesn't belong to any one Foo

Foo.MyInt = 5; //invalid; MyInt only has meaning in the context of an instance
Foo.MyStaticInt = 2; //valid

따라서 정적 멤버는 해당 유형의 단일 인스턴스에 대해 알고 있는지 여부에 관계없이 유형에 대한 지식이있는 모든 코드에 표시됩니다.

귀하의 질문에 대답하기 위해 무언가를 정적으로 표시하면 얻을 수있는 주요 이점은 소비 코드가 포함하는 객체의 인스턴스를 가지고 있는지 여부에 관계없이 유형 자체가 알려진 모든 위치에서 볼 수 있다는 것입니다. 도 있습니다 약간의 성능 이점이; 메소드가 정적 범위에 있기 때문에 (같은 클래스 또는 다른 클래스의) 다른 정적 멤버 및 매개 변수로 전달 된 모든 항목에만 액세스 할 수 있습니다. 따라서 런타임은 컨텍스트 별 상태 정보를 제공하기 위해 일반적으로 인스턴스 메소드에 대해 필요하므로 포함하는 오브젝트의 현재 인스턴스에 대한 참조를 분석 할 필요가 없습니다.

전체 클래스는 정적으로 표시 될 수도 있습니다. 이렇게하면 클래스 선언이 정적 멤버로만 구성되어 인스턴스화 할 수 없다고 컴파일러에 알립니다. 이것은 메모리에 객체의 복사본이 하나만 있는지 확인하는 쉬운 방법입니다. 클래스와 그 안의 모든 것을 정적으로 만듭니다. 그러나 이것이 그러한 요구에 가장 적합한 솔루션이라는 것은 매우 드 rare니다. 정확히 한 세트의 데이터 사본이 필요한 상황에서는 "단일"이 대신 권장됩니다. 이것은 정적이 아닌 클래스이며 정적 접근 자와 비 공용 생성자를 사용하여 단일 인스턴스에 대한 액세스를 제공합니다. 이론적으로 싱글 톤은 완전 정적 클래스와 거의 동일한 이점을 제공하지만 인스턴스 기반의 객체 지향 방식으로 클래스를 사용할 수있는 추가 기능을 제공합니다.

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