Perché i metodi statici possono utilizzare solo dati statici?


38

Non capisco perché un metodo statico non possa usare dati non statici. Qualcuno può spiegare quali sono i problemi e perché non possiamo farlo?


11
Perché esistono solo dati statici dal punto di vista dei metodi statici.
mouviciel,

4
Condividere la tua ricerca aiuta tutti. Dicci cosa hai provato e perché non ha soddisfatto le tue esigenze. Ciò dimostra che hai impiegato del tempo per cercare di aiutarti, ci salva dal ribadire risposte ovvie e soprattutto ti aiuta a ottenere una risposta più specifica e pertinente. Vedi anche Come chiedere
moscerino

19
@gnat in questo caso OP sta cercando di capire il motivo di una decisione progettuale. Cosa ti aspetti che provi in ​​questo caso?
Geek,

2
@Geek - l'esistenza di metodi statici, i dati statici sono un problema di progettazione del linguaggio. Supponendo significati standard, il fatto che i metodi statici non possano accedere ai dati dell'istanza non lo è. La limitazione è implicita dalle definizioni e da ciò che è possibile e sensato, non da alcuni difetti del progettista del linguaggio.
Steve314

6
Per parafrasare Gertrude Stein: "Non c'è questo qui".
ippopotamo,

Risposte:


73

Nella maggior parte dei linguaggi OO, quando si definisce un metodo all'interno di una classe, diventa un metodo di istanza . Quando si crea una nuova istanza di quella classe, tramite la newparola chiave, si inizializza un nuovo set di dati univoco solo per quell'istanza. I metodi appartenenti a tale istanza possono quindi funzionare con i dati definiti su di essa.

I metodi statici , al contrario, ignorano le singole istanze di classe. Il metodo statico è simile a una funzione libera in C o C ++. Non è legato a un'istanza specifica della classe. Questo è il motivo per cui non possono accedere ai valori dell'istanza. Non c'è istanza da cui prendere un valore!

I dati statici sono simili a un metodo statico. Un valore dichiarato staticnon ha un'istanza associata. Esiste per ogni istanza ed è dichiarato solo in un unico posto nella memoria. Se mai viene cambiato, cambierà per ogni istanza di quella classe.

Un metodo statico può accedere ai dati statici perché entrambi esistono indipendentemente da istanze specifiche di una classe.

Potrebbe essere utile esaminare come invocare un metodo statico, rispetto a un metodo di istanza. Diciamo che abbiamo avuto la seguente classe (usando pseudocodice simile a 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)

Aggiornare

Come viene sottolineato da COME nei commenti, un metodo statico è in grado di lavorare con dati non statici, ma deve essere passato esplicitamente. Supponiamo che la Fooclasse avesse un altro metodo:

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

Addè ancora statico e non ha valueistanze proprie, ma essendo un membro della classe Foo può accedere ai valuecampi privati del passato foo1e delle foo2istanze. In questo caso, lo stiamo usando per restituire un nuovo Foo con i valori aggiunti di entrambi i valori passati.

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

30
Espandendo "Non c'è istanza da cui prendere un valore" - anche se ci sono istanze, il metodo statico non può sapere da quale istanza prendere un valore.
Steve314

9
Questo è molto meno complicato da spiegare in lingue che non obbligano tutto a far parte di un oggetto per impostazione predefinita.
Mason Wheeler,

3
@Mason Vere parole. Linguaggi come Java fanno valere una falsa idea che una funzione sia necessariamente parte di una classe.
KChaloux,

5
Questa è una buona risposta, ma non riesce ancora a dire tutta la verità: i metodi statici possono accedere a dati non statici. Semplicemente non hanno l'oggetto implicito o il thisriferimento disponibile. Penso che sia di vitale importanza capire.
VIENI DAL

2
@COMEFROM Intendi per passaggio esplicito? Posso prenderne nota, se ti capisco correttamente. Supponevo che fosse implicito che un metodo statico potesse accedere a dati non statici passati esplicitamente, dato che qualsiasi funzione può funzionare su dati passati esplicitamente ad esso.
KChaloux,

22

Spieghiamo con un campione ipotetico.

Immagina una classe semplice:

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

Ora creiamo 2 istanze di questa classe:

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

ora, pensa: e se aggiungessimo un nuovo metodo statico all'Utente, ad esempio:

static string GetName();

e lo chiami:

string x = User::GetName()

cosa conterrebbe x? "Jim", "Bones" o qualcos'altro?

Il problema è che un metodo statico è un singolo metodo, definito sulla classe, non sugli oggetti. Di conseguenza, non sai a quale oggetto potrebbe essere applicato. Questo è il motivo per cui è una cosa speciale. È meglio pensare ai metodi statici come cose individuali, come ad esempio le funzioni in C. Il fatto che linguaggi come Java li abbia contenuti all'interno delle classi è principalmente un problema con Java che non consente a nulla di esistere al di fuori di una classe, quindi funzioni come questa devono essere forzate all'interno di una classe in qualche modo (un po 'come il modo principale () è costretto ad essere anche all'interno di una classe quando tutti i sensi dicono che dovrebbe essere una funzione singolare e autonoma).


3

Può usare i dati di campo; considera il seguente codice 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";
    }
}

Sebbene questo possa essere tecnicamente un metodo statico che utilizza dati non statici, manca il punto. Ovviamente puoi creare una nuova istanza e accedervi. Ma questo non ha nulla a che fare con l' staticintimità.
Bobson,

2
In realtà, penso che questa sia un'ottima aggiunta alla spiegazione del punto. Sottolinea il punto che il metodo statico necessita di un'istanza della classe prima di poter accedere ai dati non statici fornendo al contempo un motivo intuitivo per cui è così.
Ben Hocking,

@Bobson Dovresti leggere anche il codice e i commenti.
m3th0dman,

@BenHocking "sì", anche io penso che sia utile dire che "la variabile di istanza è sempre associata all'oggetto"
JAVA

2

I dati non statici sono associati a un'istanza della classe. I metodi (e i dati) statici non sono associati a una particolare istanza della classe. Non è necessario che sia presente un'istanza di una classe per utilizzare metodi statici su di essa. Anche se ci fossero istanze, non ci sarebbe modo per Java di garantire che stai operando sull'istanza che ti aspetti quando chiami un metodo statico. Pertanto, i metodi statici non possono avere accesso a dati non statici.


2

Penso che il problema qui sia di comprensione.

Da un punto di vista tecnico, un metodo statico chiamato dall'interno di un oggetto sarebbe in grado di vedere i campi dell'istanza. Sospetto fortemente che questo sia ciò che ha causato la domanda in primo luogo.

Il problema è che i metodi possono essere chiamati dall'esterno dell'oggetto. A quel punto non ci sono dati di istanza per fornirli - e quindi nessun modo per il compilatore di risolvere il codice. Poiché consentire i dati di istanza ha causato una contraddizione, non è necessario consentire i dati di istanza.


Non sono d'accordo. Un metodo statico non può accedere ai dati dell'istanza perché è necessario accedere ai dati dell'istanza tramite un'istanza dell'oggetto e il metodo statico non è associato a nessuna istanza (ma alla definizione della classe).
Phill W.

Ti manca il mio punto. Se viene chiamato dall'interno della classe, il compilatore potrebbe passare un puntatore all'istanza come quando non è una classe statica. Il problema sorge se viene chiamato da un'altra parte, il che significa che i metodi statici privati ​​potrebbero accedere ai dati dell'istanza (anche se essenzialmente ignorando internamente la statica).
Loren Pechtel,

Sì, il compilatore / potrebbe / ma perché dovrebbe? Passare un puntatore del genere lo riduce essenzialmente a un metodo di istanza. La tua clausola secondo cui solo i metodi privati ​​possono farlo è discutibile - le tecnologie di riflessione rendono / tutti / metodi accessibili - privati ​​o meno - rendendo questa proposta ancora più rischiosa. I nostri amici di Redmond sono andati nella direzione opposta; le loro lingue generano un avviso se si tenta di chiamare un metodo statico su un'istanza di oggetto (e non sulla classe stessa).
Phill W.

1

Pensalo come metodi statici che vivono in una dimensione non orientata agli oggetti.

Nella "dimensione orientata agli oggetti" una classe può generare multipli ego (istanze), ogni ego ha coscienza di se stesso attraverso il suo stato.

Nella dimensione piatta, non OO, una classe ignora il proprio ego che vive nella dimensione OO. Il loro mondo è piatto e procedurale, quasi come se OOP non fosse stato ancora inventato, e come se la classe fosse un piccolo programma procedurale, ei dati statici fossero solo variabili globali.


1

Penso che il modo più semplice per spiegarlo sia guardare un po 'di codice e poi considerare quali risultati ci aspettiamo che il codice produca.

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

Per completezza ecco la classe dell'auto:

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

}

come risponde alla domanda posta?
moscerino

1
@gnat Aggiornato con commenti per chiarire.
sixtyfootersdude,

1

Le altre risposte praticamente dicono tutto, tuttavia, ci sono alcuni "dettagli" che vorrei aggiungere.

I metodi statici (diciamo quelli in Java) semplicemente non hanno un oggetto implicito associato (accessibile attraverso this) i cui membri di solito puoi accedere direttamente per nome.

Ciò non significa che non possano accedere a dati non statici.

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

So che questo è solo un dettaglio, ma ho trovato la tua domanda strana quando l'ho letta. "Può usare solo dati statici" è troppo restrittivo.

A proposito, non ho testato il codice, l'ho appena scritto qui per esemplificare quello che stavo dicendo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.