Dlaczego metody statyczne mogą wykorzystywać tylko dane statyczne?

38

Nie rozumiem, dlaczego metoda statyczna nie może wykorzystywać danych niestatycznych. Czy ktoś może wyjaśnić, jakie są problemy i dlaczego nie możemy tego zrobić?

JAWA
źródło
11
Ponieważ istnieją tylko dane statyczne z punktu widzenia metod statycznych.
mouviciel
4
Udostępnianie badań pomaga wszystkim. Powiedz nam, co próbowałeś i dlaczego nie spełnia twoich potrzeb. To pokazuje, że poświęciłeś trochę czasu, aby spróbować sobie pomóc, oszczędza nam to powtarzania oczywistych odpowiedzi, a przede wszystkim pomaga uzyskać bardziej konkretną i odpowiednią odpowiedź. Zobacz także How to Ask
gnat
19
@gnat w tym przypadku OP próbuje zrozumieć przyczynę decyzji projektowej. Czego oczekujesz od niego w tej sprawie?
Geek
2
@Geek - istnienie metod statycznych, dane statyczne to problem projektowania języka. Zakładając standardowe znaczenia, fakt, że metody statyczne nie mogą uzyskać dostępu do danych instancji, nie jest. Ograniczenia są implikowane przez definicje i to, co jest możliwe i ma sens, a nie przez niektórych projektantów języków, które są marne.
Steve314,
6
Parafrazując Gertrudę Stein: „Nie ma tam tego ”.
hipopotam-tancerz

Odpowiedzi:

73

W większości języków OO, gdy definiujesz metodę wewnątrz klasy, staje się ona Metodą Instancji . Podczas tworzenia nowego wystąpienia tej klasy za pomocą newsłowa kluczowego inicjujesz nowy zestaw danych unikalny tylko dla tego wystąpienia. Metody należące do tego wystąpienia mogą następnie pracować z danymi na nim zdefiniowanymi.

Natomiast metody statyczne nie znają indywidualnych przypadków klasowych. Metoda statyczna jest podobna do funkcji swobodnej w C lub C ++. Nie jest związany z konkretną instancją klasy. Dlatego nie mogą uzyskać dostępu do wartości instancji. Nie ma instancji, z której można wziąć wartość!

Dane statyczne są podobne do metody statycznej. Zadeklarowana wartość staticnie ma powiązanej instancji. Istnieje dla każdej instancji i jest zadeklarowany tylko w jednym miejscu w pamięci. Jeśli kiedykolwiek ulegnie zmianie, zmieni się dla każdej instancji tej klasy.

Metoda statyczna może uzyskać dostęp do danych statycznych , ponieważ oba istnieją niezależnie od konkretnych instancji klasy.

Pomoże to spojrzeć na to, jak wywołujesz metodę statyczną, w porównaniu do metody instancji. Powiedzmy, że mieliśmy następującą klasę (używając pseudokodu podobnego do 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)

Aktualizacja

Jak POCHODZI punktów w komentarzach, to metoda statyczna jest zdolny do pracy z danymi non-statycznych, ale musi być przekazywane w sposób jawny. Załóżmy, że Fooklasa ma inną metodę:

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

Addjest wciąż statyczny i nie ma własnych valueinstancji, ale będąc członkiem klasy Foo, może uzyskać dostęp do prywatnych valuepól przekazywanej instancji foo1i foo2instancji. W tym przypadku używamy go, aby zwrócić nowy Foo z dodanymi wartościami obu przekazanych wartości.

Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30
KChaloux
źródło
30
Rozwijanie „Nie ma instancji, z której można by wziąć wartość” - nawet jeśli istnieją instancje, metoda statyczna nie może wiedzieć, z której instancji należy pobrać wartość.
Steve314,
9
Jest to o wiele mniej skomplikowane do objaśnienia w językach, które nie zmuszają domyślnie wszystkiego do bycia częścią obiektu.
Mason Wheeler,
3
@Mason Prawdziwe słowa. Języki takie jak Java wymuszają fałszywe przekonanie, że funkcja jest czymś, co z konieczności należy do klasy.
KChaloux
5
To dobra odpowiedź, ale wciąż nie mówi całej prawdy: metody statyczne mogą uzyskać dostęp do danych niestatycznych. Po prostu nie mają dostępnego niejawnego obiektu lub thisodwołania. Myślę, że jest to niezwykle ważne, aby zrozumieć.
PRZYJEDŹ Z
2
@COMEFROM Masz na myśli bezpośrednie przekazywanie? Mogę to zanotować, jeśli dobrze cię rozumiem. Zakładałem, że sugerowano, że metoda statyczna może uzyskać dostęp do jawnie przekazanych danych niestatycznych, biorąc pod uwagę, że każda funkcja może działać na danych jawnie do niej przekazanych.
KChaloux
22

Wyjaśnijmy to hipotetyczną próbką.

Wyobraź sobie prostą klasę:

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

Teraz tworzymy 2 wystąpienia tej klasy:

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

teraz pomyśl - co jeśli dodamy nową metodę statyczną do użytkownika, np .:

static string GetName();

i nazywacie to:

string x = User::GetName()

co by zawierał x? „Jim”, „Bones” czy coś jeszcze?

Problem polega na tym, że metoda statyczna jest pojedynczą metodą zdefiniowaną w klasie, a nie obiektami. W rezultacie nie wiesz, do którego obiektu może się odnosić. Właśnie dlatego jest to wyjątkowa rzecz. Metody statyczne najlepiej traktować jako pojedyncze rzeczy, na przykład funkcje w C. To, że języki takie jak Java zawierają je w klasach, jest głównie problemem z tym, że Java nie pozwala, aby cokolwiek istniało poza klasą, więc takie funkcje muszą być w jakiś sposób wymuszone w klasie (trochę tak, jak musi być main ()) również wewnątrz klasy, kiedy wszystko rozumie, że powinna to być pojedyncza, samodzielna funkcja).

gbjbaanb
źródło
2

Dane niestatyczne są powiązane z instancją klasy. Metody statyczne (i dane) nie są powiązane z konkretnym wystąpieniem klasy. Nie musi istnieć instancja klasy, aby używać na niej metod statycznych. Nawet gdyby istniały instancje, Java nie byłaby w stanie zagwarantować działania na instancji, której oczekujesz po wywołaniu metody statycznej. Dlatego metody statyczne nie mogą mieć dostępu do danych niestatycznych.

smp7d
źródło
2

Może korzystać z danych terenowych; rozważ następujący kod java:

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";
    }
}
m3th0dman
źródło
Chociaż technicznie może to być metoda statyczna z wykorzystaniem danych niestatycznych, nie ma sensu. Oczywiście możesz utworzyć nową instancję i uzyskać do niej dostęp. Ale to nie ma nic wspólnego z staticnicością.
Bobson,
2
Właściwie uważam, że jest to bardzo dobry dodatek do wyjaśnienia tego. Podkreśla to, że metoda statyczna potrzebuje wystąpienia klasy, zanim będzie mogła uzyskać dostęp do danych niestatycznych, podając jednocześnie intuicyjny powód.
Ben Hocking
@ Bobson Powinieneś również przeczytać kod i komentarze.
m3th0dman
@BenHocking „tak”, nawet myślę, że warto powiedzieć, że „zmienna instancji jest zawsze powiązana z obiektem”
JAVA
2

Myślę, że tutaj chodzi o zrozumienie.

Z technicznego punktu widzenia metoda statyczna wywoływana z obiektu byłaby w stanie zobaczyć pola instancji. Podejrzewam, że właśnie to spowodowało pytanie.

Problem polega na tym, że metody można wywoływać spoza obiektu. W tym momencie nie ma danych instancji do ich dostarczenia - a zatem kompilator nie może rozwiązać kodu. Ponieważ zezwolenie na dane instancji spowodowało sprzeczność, nie możemy pozwolić na dane instancji.

Loren Pechtel
źródło
Nie zgadzam się. Metoda statyczna nie może uzyskać dostępu do danych instancji, ponieważ do danych instancji należy uzyskać dostęp za pośrednictwem instancji obiektu, a metoda statyczna nie jest powiązana z żadną instancją (ale z definicją klasy).
Phill W.
Tęsknisz za moim celem. Jeśli zostanie wywołany z klasy, kompilator może przekazać wskaźnik instancji, tak jak robi to, gdy nie jest to klasa statyczna. Problem pojawia się, jeśli jest wywoływany z innego miejsca - co oznacza, że ​​prywatne metody statyczne mogą uzyskiwać dostęp do danych instancji (choć wewnętrznie zasadniczo ignorują dane statyczne).
Loren Pechtel
Tak, kompilator / mógłby / ale dlaczego? Przekazanie takiego wskaźnika zasadniczo redukuje go do metody instancji. Twoje zastrzeżenie, że mogą to robić tylko prywatne metody, jest dyskusyjne - technologie refleksji sprawiają, że / all / metody są dostępne - prywatne lub nie - czyniąc z tego jeszcze bardziej ryzykowną propozycję. Nasi przyjaciele w Redmond poszli w innym kierunku; ich języki generują ostrzeżenie, jeśli próbujesz wywołać metodę statyczną przeciwko instancji obiektu (a nie samej klasie).
Phill W.
1

Pomyśl o tym jak o metodach statycznych żyjących w wymiarze nieorientowanym obiektowo.

W „zorientowanym obiektowo wymiarze” klasa może spawnować wiele ego (instancji), każde ego ma sumienie siebie poprzez swój stan.

W płaskim, nie-OO-wymiarze klasa nie jest świadoma swoich ego żyjących w wymiarze OO. Ich świat jest płaski i proceduralny, prawie tak, jakby OOP nie został jeszcze wynaleziony, i jakby klasa była małym programem proceduralnym, a dane statyczne były tylko zmiennymi globalnymi.

Tulains Córdova
źródło
1

Myślę, że najprostszym sposobem na wyjaśnienie tego jest przyjrzenie się kodowi, a następnie zastanowienie się, jakie wyniki spodziewalibyśmy się, że kod wygeneruje.

// 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.  

Dla kompletności oto klasa samochodów:

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;
    }

}
sześćdziesiąt stóp
źródło
Jak to odpowiada na zadane pytanie?
komara
1
@gnat Zaktualizowano z komentarzami w celu wyjaśnienia.
sixtyfootersdude
1

Pozostałe odpowiedzi w zasadzie mówią wszystko, jednak jest trochę „szczegółów”, które chciałbym dodać.

Metody statyczne (powiedzmy te w Javie) po prostu nie mają powiązanego z nimi niejawnego obiektu (dostępnego przez this), do którego członków można uzyskać dostęp bezpośrednio bezpośrednio po nazwie.

To nie znaczy, że nie mogą uzyskać dostępu do danych niestatycznych.

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

Wiem, że to tylko szczegół, ale moje pytanie było dziwne, gdy je przeczytałem. „Może używać tylko danych statycznych” jest zbyt restrykcyjne.

Nawiasem mówiąc, nie testowałem kodu, po prostu napisałem go tutaj, aby zilustrować to, co mówiłem.

Pedro Henrique A. Oliveira
źródło