Ich habe eine Klasse, die einige statische Methoden haben muss. Innerhalb dieser statischen Methoden muss ich die Methode getClass () aufrufen, um den folgenden Aufruf auszuführen:
public static void startMusic() {
URL songPath = getClass().getClassLoader().getResource("background.midi");
}
Eclipse sagt mir jedoch:
Cannot make a static reference to the non-static method getClass()
from the type Object
Was ist der geeignete Weg, um diesen Fehler bei der Kompilierung zu beheben?
java
static-methods
Rama
quelle
quelle
getResource()
bevor eine Instanz einer benutzerdefinierten Klasse (z. B. Nicht-J2SE) vorhanden ist, schlägt manchmal fehl. Das Problem ist, dass die JRE zu diesem Zeitpunkt den Bootstrap-Klassenlader verwendet, der keine Anwendungsressourcen im Klassenpfad (des Bootstrap-Laders) hat.Antworten:
Die Antwort
Verwenden Sie einfach
TheClassName.class
anstelle vongetClass()
.Logger deklarieren
Da dies für einen bestimmten Anwendungsfall so viel Aufmerksamkeit erhält - um eine einfache Möglichkeit zum Einfügen von Protokolldeklarationen zu bieten -, dachte ich, ich würde meine Gedanken dazu hinzufügen. Protokoll-Frameworks erwarten häufig, dass das Protokoll auf einen bestimmten Kontext beschränkt ist, z. B. einen vollständig qualifizierten Klassennamen. Sie können also nicht ohne Änderungen kopiert werden. Vorschläge für einfügesichere Protokolldeklarationen sind in anderen Antworten enthalten, haben jedoch Nachteile wie das Aufblasen von Bytecode oder das Hinzufügen von Introspection zur Laufzeit. Ich empfehle diese nicht. Das Kopieren und Einfügen ist ein Problem des Editors , daher ist eine Editorlösung am besten geeignet.
In IntelliJ empfehle ich das Hinzufügen einer Live-Vorlage:
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class);
als Vorlage Text.className()
Wenn Sie jetzt eingeben, wird
log<tab>
es automatisch auf erweitertUnd formatieren und optimieren Sie die Importe automatisch für Sie neu.
quelle
Log
in Android, für das ein Tag angegeben werden muss, normalerweise der Klassenname. Und es gibt wahrscheinlich andere Beispiele. Natürlich können Sie dafür ein Feld deklarieren (was üblich ist), aber das ist immer noch Kopieren und Einfügen.CLASS
einclassName()
. Dadurch wird sichergestellt, dass $ CLASS $ tatsächlich durch den Klassennamen ersetzt wird, andernfalls wird es nur leer ausgegeben.Was das Codebeispiel in der Frage betrifft, besteht die Standardlösung darin, die Klasse explizit mit ihrem Namen zu referenzieren, und es ist sogar möglich, auf einen
getClassLoader()
Aufruf zu verzichten:Dieser Ansatz hat immer noch die Rückseite, dass er nicht sehr sicher gegen Kopier- / Einfügefehler ist, falls Sie diesen Code in eine Reihe ähnlicher Klassen replizieren müssen.
Und was die genaue Frage in der Überschrift betrifft, gibt es im nebenstehenden Thread einen Trick :
Es verwendet eine verschachtelte anonyme
Object
Unterklasse, um den Ausführungskontext abzurufen. Dieser Trick hat den Vorteil, dass er kopier- und einfügesicher ist ...Vorsicht bei der Verwendung in einer Basisklasse, von der andere Klassen erben:
Es ist auch erwähnenswert, dass, wenn dieses Snippet als statische Methode einer Basisklasse geformt ist, der
currentClass
Wert immer eine Referenz auf diese Basisklasse ist und nicht auf eine Unterklasse, die diese Methode möglicherweise verwendet.quelle
Class.getResource()
Kann sich übrigens etwas anders verhalten alsClassLoader.getResource()
; Siehe stackoverflow.com/a/676273In Java7 + können Sie dies in statischen Methoden / Feldern tun:
quelle
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
Ich habe selbst damit gerungen. Ein guter Trick besteht darin, den aktuellen Thread zu verwenden, um in einem statischen Kontext einen ClassLoader abzurufen. Dies funktioniert auch in einem Hadoop MapReduce. Andere Methoden funktionieren bei lokaler Ausführung, geben jedoch bei Verwendung in MapReduce einen Null-InputStream zurück.
quelle
Verwenden Sie einfach ein Klassenliteral, dh
NameOfClass.class
quelle
getClass()
Die Methode wird in der Objektklasse mit der folgenden Signatur definiert:Da es nicht als definiert ist
static
, können Sie es nicht innerhalb eines statischen Codeblocks aufrufen. Weitere Informationen finden Sie in diesen Antworten: Q1 , Q2 , Q3 .Wenn Sie sich in einem statischen Kontext befinden, müssen Sie den Klassenliteralausdruck verwenden, um die Klasse abzurufen. Grundsätzlich müssen Sie also Folgendes tun:
Diese Art von Ausdruck wird als Klassenliterale bezeichnet und im Java Language Specification Book wie folgt erläutert :
Informationen zu diesem Thema finden Sie auch in der API-Dokumentation für Class.
quelle
Versuch es
Oder
quelle
[1]
alle Protokollnachrichten unterThread
Android 4.4.4 als Quelle gemeldet werden .[2]
scheint sowohl auf Android als auch auf OpenJRE das richtige Ergebnis zu liefern.Angenommen, es gibt eine Utility-Klasse, dann wäre der Beispielcode -
CustomLocation - Wenn eine Ordnerstruktur innerhalb der Ressourcen vorhanden ist, entfernen Sie dieses Zeichenfolgenliteral.
quelle
Versuchen Sie so etwas. Für mich geht das. Logg (Klassenname)
quelle