Non capisco perché un metodo statico non possa usare dati non statici. Qualcuno può spiegare quali sono i problemi e perché non possiamo farlo?
Non capisco perché un metodo statico non possa usare dati non statici. Qualcuno può spiegare quali sono i problemi e perché non possiamo farlo?
Risposte:
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 new
parola 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 static
non 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)
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 Foo
classe 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 value
istanze proprie, ma essendo un membro della classe Foo può accedere ai value
campi privati del passato foo1
e delle foo2
istanze. 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
this
riferimento disponibile. Penso che sia di vitale importanza capire.
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).
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";
}
}
static
intimità.
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.
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.
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.
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;
}
}
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.