정적 메소드가 정적 데이터 만 사용할 수있는 이유는 무엇입니까?


38

정적 메소드가 정적이 아닌 데이터를 사용할 수없는 이유를 이해하지 못합니다. 아무도 문제가 무엇인지, 왜 우리가 할 수 없는지 설명 할 수 있습니까?


11
정적 메소드의 관점에서 정적 데이터 만 존재하기 때문입니다.
mouviciel

4
연구 결과를 공유하면 모든 사람에게 도움이됩니다. 당신이 무엇을 시도했고 왜 그것이 당신의 요구를 충족시키지 못했는지 알려주십시오. 이것은 당신이 시간을내어 자신을 돕기 위해 노력했고, 분명한 답변을 되풀이하는 것을 막아 주며, 무엇보다도보다 구체적이고 관련있는 답변을 얻는 데 도움이됩니다. 또한 묻는 방법
gnat

19
이 경우에 @gnat OP는 디자인 결정의 원인을 이해하려고합니다. 이 경우에 그가 무엇을 시도 할 것이라고 기대하십니까?
Geek

2
@Geek-정적 메소드의 존재, 정적 데이터는 언어 설계 문제입니다. 표준 의미를 가정 할 때 정적 메소드가 인스턴스 데이터에 액세스 할 수 없다는 사실은 그렇지 않습니다. 이러한 제한은 일부 언어 디자이너의 우화가 아니라 정의와 가능하고 의미가있는 것으로 암시됩니다.
Steve314

6
Gertrude Stein의 말을 바꾸려면 : " 이것은 없습니다."
hippo-dancer

답변:


73

대부분의 OO 언어에서 클래스 내부에 메소드를 정의하면 인스턴스 메소드가 됩니다. 키워드 를 통해 해당 클래스 의 새 인스턴스 를 만들면 new해당 인스턴스에만 고유 한 새 데이터 세트가 초기화됩니다. 그러면 해당 인스턴스에 속하는 메소드가 사용자가 정의한 데이터로 작업 할 수 있습니다.

대조적으로 정적 메소드 는 개별 클래스 인스턴스를 무시합니다. 정적 메소드는 C 또는 C ++의 무료 함수와 유사합니다. 클래스의 특정 인스턴스화와 관련이 없습니다. 이것이 인스턴스 값에 액세스 할 수없는 이유입니다. 가치를 얻을 수있는 사례가 없습니다!

정적 데이터 는 정적 방법과 유사합니다. 선언 된 값 static에는 연관된 인스턴스가 없습니다. 모든 인스턴스에 대해 존재 하며 메모리의 단일 위치에서만 선언됩니다. 변경되면 해당 클래스의 모든 인스턴스에 대해 변경됩니다.

정적 메서드가 액세스 할 수있는 정적 데이터를 둘 다 클래스의 특정 인스턴스 독립적으로 존재하기 때문이다.

인스턴스 메소드와 비교하여 정적 메소드를 호출하는 방법을 살펴 보는 것이 도움이 될 수 있습니다. Java와 유사한 의사 코드를 사용하여 다음과 같은 클래스가 있다고 가정 해 보겠습니다.

class Foo {
    // This static value belongs to the class Foo
    public static final string name = "Foo";

    // This non-static value will be unique for every instance
    private int value;

    public Foo(int value) {
         this.value = value;
    }

    public void sayValue() {
        println("Instance Value: " + value);
    }

    public static void sayName() {
        println("Static Value: " + name);
    }
}

Foo foo1 = new Foo(10);
Foo foo2 = new Foo(20);

foo1.sayValue(); // Prints "Instance Value: 10" - called on foo1
foo2.sayValue(); // Prints "Instance Value: 20" - called on foo2

Foo.sayName(); // Prints "Static Value: Foo" - called on Foo (not foo1 or foo2)

최신 정보

주석에서 COME FROM이 지적한 것처럼 정적 메소드 비 정적 데이터로 작업 할 수 있지만 명시 적으로 전달해야합니다. Foo클래스에 다른 메소드가 있다고 가정 해 봅시다 .

public static Foo Add(Foo foo1, Foo foo2) {
    return new Foo(foo1.value + foo2.value);
}

Add여전히 정적이며 value자체 인스턴스 가 없지만 Foo 클래스의 멤버 value는 전달 된 인스턴스 foo1foo2인스턴스 의 개인 필드에 액세스 할 수 있습니다 . 이 경우, 전달 된 두 값의 값이 추가 된 Foo 값 을 반환하는 데 사용 합니다.

Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30

30
에 확장 "에서 값을 할 경우도 없다"- 인스턴스가있는 경우에도, 정적 방법을 알 수 있는 의 값을 취할 인스턴스입니다.
Steve314

9
기본적으로 모든 것을 객체의 일부로 강제하지 않는 언어에서는 설명하기가 훨씬 복잡합니다.
메이슨 휠러

3
@Mason 진정한 단어. Java와 같은 언어는 함수가 클래스에 속해야한다는 잘못된 개념을 강요합니다.
KChaloux

5
이것은 정답이지만 여전히 진실을 밝히지 못합니다. 정적 메소드 비 정적 데이터에 액세스 할 수 있습니다. 그들은 암시 적 객체 또는 참조를 this사용할 수 없습니다. 이해하는 것이 매우 중요하다고 생각합니다.
에서 오는

2
@COMEFROM 명시적인 전달을 의미합니까? 내가 당신을 올바르게 이해하고 있다면 그것을 기록 할 수 있습니다. 나는 정적 방법은 명시 적으로 주어진, 비 정적 데이터를 전달 액세스 할 수 있음을 암시 한 것으로 어떤 기능이 명시 적으로 전달되는 데이터에 대한 작업을 수행 할 수 있습니다.
KChaloux

22

가상의 샘플로 설명해 드리겠습니다.

간단한 수업을 상상해보십시오.

class User
{
User(string n) { name = n; };
string name;
}

이제이 클래스의 인스턴스를 2 개 만듭니다.

User Bones = new User("Bones");
User Jim = new User("Jim");

이제 생각하십시오-User에 새로운 정적 메소드를 추가하면 다음과 같이됩니다.

static string GetName();

그리고 당신은 그것을 호출 :

string x = User::GetName()

x는 무엇을 포함 할 것인가? "짐", "뼈"또는 다른 것?

문제는 정적 메소드가 객체가 아니라 클래스에 정의 된 단일 메소드라는 것입니다. 결과적으로 어떤 객체에 적용되는지 알 수 없습니다. 이것이 특별한 이유입니다. 정적 메소드를 C의 함수와 같은 개별적인 것으로 생각하는 것이 가장 좋습니다. Java와 같은 언어가 클래스 내부에 포함되어 있다는 것은 주로 클래스 외부에 존재하는 것을 허용하지 않는 Java의 문제이므로 이와 같은 함수는 어떤 방식으로 클래스 내부에서 강제해야합니다 (main ()이 강제로 수행되는 것과 약간 비슷합니다) 모든 의미에서 단일, 독립형 기능이어야한다고 말할 때 클래스 내부에서도).


2

비 정적 데이터는 클래스의 인스턴스와 연결됩니다. 정적 메소드 (및 데이터)는 클래스의 특정 인스턴스와 연관되지 않습니다. 정적 메소드를 사용하기 위해 클래스의 인스턴스가 필요하지 않습니다. 인스턴스가 있더라도 Java가 정적 메소드를 호출 할 때 예상 한 인스턴스에서 작동하고 있음을 보장 할 방법이 없습니다. 따라서 정적 메소드는 비 정적 데이터에 액세스 할 수 없습니다.


2

필드 데이터를 사용할 수 있습니다. 다음 자바 코드를 고려하십시오.

class MyBean {
    private String myString;

    static void myStaticMethod() {
        myString = "tada";/*not allowed; if this was possible how would 
                           be different from a field without static?*/

        MyBean myBean = new MyBean();//allowed if associated with an instance
        myBean.myString = "tada";
    }
}

이것은 기술적 으로 비 정적 데이터를 사용하는 정적 방법 일 수 있지만 요점을 놓치게됩니다. 물론 새 인스턴스를 만들어 액세스 할 수 있습니다. 그러나 그것은 전적으로 관련이 없습니다 static.
밥슨

2
사실, 나는 이것이 요점을 설명하는 데 아주 좋은 추가라고 생각합니다. 정적 메소드가 정적이 아닌 데이터에 액세스하기 전에 클래스의 인스턴스가 필요하다는 점을 강조하면서 그 이유를 직관적으로 알 수 있습니다.
Ben Hocking

@Bobson 코드와 주석도 읽어야합니다.
m3th0dman

@BenHocking "yes"조차도 "인스턴스 변수는 항상 객체와 관련되어"있다고 말하는 것이 좋은 지적이라고 생각합니다.
JAVA

2

여기서 문제는 이해의 문제라고 생각합니다.

기술적 인 관점에서 객체 내에서 호출 된 정적 메소드는 인스턴스 필드를 볼 수 있습니다. 이것이 처음에 문제를 일으킨 원인이라고 생각합니다.

문제는 객체 외부에서 메소드를 호출 할 수 있다는 것입니다. 이 시점에서 인스턴스 데이터를 제공 할 인스턴스 데이터가 없으므로 컴파일러가 코드를 해결할 수있는 방법이 없습니다. 인스턴스 데이터를 허용하면 모순이 발생하므로 인스턴스 데이터를 허용해서는 안됩니다.


동의하지 않습니다. 인스턴스 데이터는 객체의 인스턴스를 통해 액세스해야하고 정적 메서드는 지정된 인스턴스와 연결되어 있지 않지만 클래스 정의와 연결되어 있기 때문에 정적 메서드는 인스턴스 데이터에 액세스 할 수 없습니다.
Phill W.

내 요점을 그리워 경우 이 클래스 내에서라고는 정적 클래스 않다 때하는 것처럼 컴파일러는 인스턴스 포인터를 전달할 수 있습니다. 다른 곳에서 호출하면 문제가 발생합니다. 즉, 비공개 정적 메서드는 내부적으로 기본적으로 정적을 무시해도 인스턴스 데이터에 액세스 할 수 있음을 의미합니다.
Loren Pechtel

예, 컴파일러 / could /이지만 왜 그래야합니까? 이러한 포인터를 전달하면 기본적으로 포인터를 인스턴스 메소드로 줄입니다. 이를 수행 할 수있는 유일한 방법은 반사 기술이 / all / 방법에 접근 가능하도록 (비공개 여부)-더 위험한 제안입니다. 레드몬드에있는 우리의 친구들은 다른 방향으로갔습니다. 클래스 자체가 아닌 객체 인스턴스에 대해 정적 메서드를 호출하려고하면 해당 언어에서 경고가 발생합니다.
Phill W.

1

객체 지향이 아닌 차원에 사는 정적 메소드라고 생각하십시오.

"객체 지향 차원"에서 클래스는 여러 자아 (인스턴스)를 생성 할 수 있으며, 각 자아는 상태를 통해 양심을 갖습니다.

평평하고 비 OO 차원에서 클래스는 자신의 자아가 OO 차원에 살고 있다는 것을 잊어 버립니다. 그들의 세계는 거의 OOP가 아직 발명되지 않은 것처럼, 클래스가 작은 절차 적 프로그램 인 것처럼 정적 데이터는 절차 적이며 정적 데이터는 전역 변수 일뿐입니다.


1

이것을 설명하는 가장 쉬운 방법은 일부 코드를보고 코드가 어떤 결과를 기대할 수 있는지 고려하는 것입니다.

// Create three new cars.  Cars have a name attribute.  
Car car1 = new Car("Mazda3");
Car car2 = new Car("FordFocus");
Car car3 = new Car("HondaFit");

// Now we would like to print the names of some cars: 
// First off why don't we try this: 

Car.printCarName();

// Expected behaviour: 
// If we think about what we are trying to do here it doesn't
// really make sense.  What instance of car name should this 
// print?  Should it print Mazda3?  FordFoucs?
// What is the expected behaviour?  If we are going to have a
// static call on car call printCarName it should probably do
// something like print all car names or a random car name or
// throw an error.  


//Now lets try this instead: 

Car.printCarName(car1);

// Expected Behaviour: 
// Luckily the expected behaviour is very clear here.  This
// should print Mazda3.  This works as expected.  


// Finally lets try this: 

car1.printMyName();

// Expected Behaviour:
// Same as previous example, however this is the *right* way
// to do it.  

완전성을 위해 여기에 자동차 등급이 있습니다.

public class Car{

    public String name;

    public Car(String name){
        this.name = name;
    }

    public static printCarName(){
        print "Not sure what to do here...  Don't know which car you are talking about.";
    }

    public static printCarName(Car c){
        print c.name;
    }

    public /*NOT static*/ printMyName(){
        print this.name;
    }

}

이것은 질문에 어떻게 대답합니까?
gnat

1
@gnat 명확하게 설명으로 업데이트되었습니다.
sixtyfootersdude

1

다른 답변은 거의 모든 것을 말하지만, 추가하고 싶은 "세부 사항"이 있습니다.

정적 메소드 (예 : Java의 메소드)에는 this일반적으로 이름으로 직접 액세스 할 수있는 멤버에 연결된 암시 적 객체가 없습니다 (를 통해 액세스 가능 ).

비 정적 데이터에 액세스 할 수 없다는 의미는 아닙니다.

class MyClass {
  public static void foo(MyOtherClass object) {
    System.out.println(object.member);
  }
}
class MyOtherClass { public int member = 10; }

나는 이것이 세부 사항이라는 것을 알고 있지만 그것을 읽을 때 귀하의 질문이 이상하다는 것을 알았습니다. "정적 데이터 만 사용할 수 있습니다"는 너무 제한적입니다.

그건 그렇고, 나는 코드를 테스트하지 않았으며, 내가 말한 것을 예시하기 위해 여기에 썼습니다.

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