Es kann kein statischer Verweis auf die nicht statische Methode erstellt werden

102

Erstellen einer mehrsprachigen Anwendung in Java. Beim Einfügen eines Zeichenfolgenwerts aus einer R.stringRessourcen-XML-Datei wird ein Fehler angezeigt :

public static final String TTT =  (String) getText(R.string.TTT);

Dies ist die Fehlermeldung:

Fehler: Es kann kein statischer Verweis auf die nicht statische Methode getText (int) vom Typ Context erstellt werden

Wie wird das verursacht und wie kann ich es lösen?

Chen M.
quelle
1
Warum muss es für eine mehrsprachige Anwendung statisch sein? Verstehe nicht wirklich.
xil3
3
Speichern Sie niemals Zeichenfolgenressourcen in statischen Datenelementen. Fordern getString()Sie sie immer an, wenn Sie sie brauchen. Auf diese Weise passt sich Ihre Anwendung ordnungsgemäß an Benutzer an, die ihre ausgewählte Sprache ändern.
CommonsWare

Antworten:

143

Da getText()es nicht statisch ist, können Sie es nicht über eine statische Methode aufrufen.

Um zu verstehen warum, muss man den Unterschied zwischen den beiden verstehen.

Instanzmethoden (nicht statisch) arbeiten mit Objekten eines bestimmten Typs (der Klasse). Diese werden mit dem neuen wie folgt erstellt:

SomeClass myObject = new SomeClass();

Um eine Instanzmethode aufzurufen, rufen Sie sie auf der Instanz ( myObject) auf:

myObject.getText(...)

Eine statische Methode / ein statisches Feld kann jedoch nur für den Typ direkt aufgerufen werden. Sagen Sie Folgendes: Die vorherige Anweisung ist nicht korrekt. Man kann auch auf statische Felder mit einer Objektreferenz wie verweisen myObject.staticMethod() , dies wird jedoch nicht empfohlen, da nicht klar ist, dass es sich um Klassenvariablen handelt.

... = SomeClass.final

Und die beiden können nicht zusammenarbeiten, da sie unterschiedliche Datenräume (Instanzdaten und Klassendaten) bearbeiten.

Lass mich versuchen zu erklären. Betrachten Sie diese Klasse (Pseudocode):

class Test {
     string somedata = "99";
     string getText() { return somedata; } 
     static string TTT = "0";
}

Jetzt habe ich folgenden Anwendungsfall:

Test item1 = new Test();
 item1.somedata = "200";

 Test item2 = new Test();

 Test.TTT = "1";

Was sind die Werte?

Gut

in item1 TTT = 1 and somedata = 200
in item2 TTT = 1 and somedata = 99

Mit anderen Worten, TTTist ein Datum, das von allen Instanzen des Typs gemeinsam genutzt wird. Es macht also keinen Sinn zu sagen

class Test {
         string somedata = "99";
         string getText() { return somedata; } 
  static string TTT = getText(); // error there is is no somedata at this point 
}

Die Frage ist also, warum TTT statisch ist oder warum getText () nicht statisch ist.

Entfernen Sie das staticund es sollte diesen Fehler überwinden - aber ohne zu verstehen, was Ihr Typ tut, ist es nur ein Heftpflaster bis zum nächsten Fehler. Was sind die Anforderungen dafür getText(), dass es nicht statisch sein muss?

Preet Sangha
quelle
es ist statisch, weil ich es aus mehreren Dateien in meinem Projekt aufrufe. Als ich die "statische" entfernt habe, ist der Fehlercode weg, aber jetzt habe ich viele Fehler in anderen Dateien, die diese Variable verwenden.
Chen M
Aber das ist mein Punkt. Sie müssen verstehen, wann die beiden verwendet werden können.
Preet Sangha
Wenn ich die Zeile "Constants notifications_values ​​= new Constants (); zu meiner Hauptaktivitätsklasse hinzufüge, wird sie in Ordnung kompiliert, aber im Emulator stürzt sie ab, wenn diese Aktivität ausgeführt wird
Chen M
11

Es gibt bereits einige gute Antworten mit Erklärungen, warum die Mischung der nicht statischen ContextMethode getText()nicht mit Ihrer verwendet werden kann static final String.

Eine gute Frage ist: Warum möchten Sie das tun? Sie versuchen, a Stringaus Ihrer stringsRessource zu laden und seinen Wert in ein public staticFeld einzufügen. Ich gehe davon aus, dass dies so ist, dass einige Ihrer anderen Klassen darauf zugreifen können? In diesem Fall ist dies nicht erforderlich. Übergeben Sie stattdessen ein Contextin Ihre anderen Klassen und rufen Sie von dort context.getText(R.string.TTT)aus an.

public class NonActivity {

    public static void doStuff(Context context) {
        String TTT = context.getText(R.string.TTT);
        ...
    }
}

Und um dies von Ihrem zu nennen Activity:

NonActivity.doStuff(this);

Auf diese Weise können Sie auf Ihre StringRessource zugreifen , ohne ein public staticFeld verwenden zu müssen.

dave.c
quelle
1
Vielen Dank, ich habe alle Dateien gemäß Ihrer Empfehlung geändert.
Chen M
Ich habe versucht, dies zu tun, aber für ein String-Array und mit String a[] = context.getTextArray(R.array.myStringArray); ; es gibt mir jedoch einen Fehler The method getTextArray(int) is undefined for the type Context- warum sollte es undefiniert sein, während es mit getText funktioniert?
glückverheißend99
1
@ auspicious99 einfach, weil a Contextkeine Methode namens hat getTextArray, aber hat getText. Vielleicht denken Sie daran, Resourceswas hatgetTextArray
dave.c
Ah danke! Übergeben einer Ressource anstelle eines Kontexts (von der Aktivität zur Nichtaktivität), und mein getStringArray hat funktioniert.
glückverheißend99
9

für andere, die dies in der Suche finden:

Ich bekomme diese oft, wenn ich versehentlich eine Funktion mit dem Klassennamen und nicht mit dem Objektnamen aufrufe. Dies geschieht normalerweise, weil ich ihnen zu ähnliche Namen gebe: P.

dh:

MyClass myclass = new MyClass();

// then later

MyClass.someFunction();

Dies ist offensichtlich eine statische Methode. (gut für etwas) Aber was ich wirklich tun wollte (in den meisten Fällen war)

myclass.someFunction();

Es ist so ein dummer Fehler, aber alle paar Monate verschwende ich ungefähr 30 Minuten damit, mit Vars in den "MyClass" -Definitionen herumzuspielen, um herauszufinden, was ich falsch mache, wenn es wirklich nur ein Tippfehler ist.

Witziger Hinweis: Der Stapelüberlauf hebt die Syntax hervor, um den Fehler hier wirklich offensichtlich zu machen.

SpiRail
quelle
Hebt Ihre IDE dies nicht auch hervor? Ich denke, Sie können es dafür konfigurieren :)
Matthias Meid
2

Sie können Ihre Variable entweder nicht statisch machen

public final String TTT =  (String) getText(R.string.TTT);

oder machen Sie die "getText" -Methode statisch (wenn überhaupt möglich)

Kellindil
quelle
2

getText ist Mitglied Ihrer Aktivität und muss daher aufgerufen werden, wenn "this" vorhanden ist. Ihre statische Variable wird initialisiert, wenn Ihre Klasse geladen wird, bevor Ihre Aktivität erstellt wird.

Da die Variable aus einer Ressourcenzeichenfolge initialisiert werden soll, kann sie nicht statisch sein. Wenn Sie möchten, dass es statisch ist, können Sie es mit dem String-Wert initialisieren.

Robby Pond
quelle
2

Sie können mit der nicht statischen Methode nicht auf statische Variablen verweisen. Um dies zu verstehen, müssen Sie den Unterschied zwischen statisch und nicht statisch verstehen.

Statische Variablen sind Klassenvariablen. Sie gehören zur Klasse mit ihrer einzigen Instanz, die nur bei der ersten erstellt wird. Nicht statische Variablen werden jedes Mal initialisiert, wenn Sie ein Objekt der Klasse erstellen.

Wenn Sie nun zu Ihrer Frage kommen und den Operator new () verwenden, erstellen wir eine Kopie aller nicht statischen Dateien für jedes Objekt. Dies ist jedoch bei statischen Feldern nicht der Fall. Aus diesem Grund tritt ein Fehler bei der Kompilierung auf, wenn Sie auf eine statische Variable aus einer nicht statischen Methode verweisen.

Krishna
quelle
0

Diese Frage ist nicht neu und die vorhandenen Antworten geben einen guten theoretischen Hintergrund. Ich möchte nur eine pragmatischere Antwort hinzufügen.

getText ist eine Methode der abstrakten Context-Klasse. Um sie aufzurufen, benötigt man eine Instanz ihrer Unterklasse (Aktivität, Dienst, Anwendung oder andere). Das Problem ist, dass die öffentlichen statischen endgültigen Variablen initialisiert werden, bevor eine Instanz von Context erstellt wird.

Es gibt verschiedene Möglichkeiten, dies zu lösen:

  1. Machen Sie die Variable zu einer Mitgliedsvariablen (Feld) der Aktivität oder einer anderen Unterklasse des Kontexts, indem Sie den statischen Modifikator entfernen und in den Klassenkörper einfügen.
  2. Halten Sie es statisch und verzögern Sie die Initialisierung auf einen späteren Zeitpunkt (z. B. in der onCreate-Methode).
  3. Machen Sie es zu einer lokalen Variablen anstelle der tatsächlichen Verwendung.
dev.bmax
quelle