Jak można uzyskać nazwę klasy z metody statycznej w tej klasie. Na przykład
public class MyClass {
public static String getClassName() {
String name = ????; // what goes here so the string "MyClass" is returned
return name;
}
}
Aby umieścić to w kontekście, naprawdę chcę zwrócić nazwę klasy jako część komunikatu w wyjątku.
try{ throw new RuntimeEsception();} catch(RuntimeEcxeption e){return e.getstackTrace()[1].getClassName();
}Odpowiedzi:
Aby poprawnie obsługiwać refaktoryzację (zmiana nazwy klasy), należy użyć:
lub (dzięki @James Van Huis ):
źródło
Rób to, co mówi zestaw narzędzi. Nie rób czegoś takiego:
źródło
getClass
zwraca typ środowiska wykonawczego, więc nie może być statyczny.W Javie 7+ możesz to zrobić w statycznej metodzie / polach:
źródło
Reflection.getCallerClass()
. Ale daje ostrzeżenie o byciu w paczkach „słonecznych”. To może być lepsze rozwiązanie.Reflection.getCallerClass()
rzecz. Jest to trochę skomplikowane dla jego trywialnej operacji, tj.Optional<Class<?>> myself = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map(StackWalker.StackFrame::getDeclaringClass) .findFirst());
, Ale oczywiście wiąże się to z faktem, że będzie znacznie potężniejszy.Mamy więc sytuację, w której musimy statycznie uzyskać obiekt klasy lub pełną / prostą nazwę klasy bez wyraźnego użycia
MyClass.class
składni.W niektórych przypadkach może być bardzo przydatny, np. Wystąpienie programu rejestrującego kotlin funkcje wyższego poziomu (w tym przypadku kotlin tworzy statyczną klasę Java niedostępną z kodu kotlin).
Mamy kilka różnych wariantów uzyskiwania tych informacji:
new Object(){}.getClass().getEnclosingClass();
zauważył Tom Hawtin - tackline
getClassContext()[0].getName();
zSecurityManager
odnotowanej przez Christoffera
new Throwable().getStackTrace()[0].getClassName();
według hrabiego Ludwiga
Thread.currentThread().getStackTrace()[1].getClassName();
z Keksi
i wreszcie niesamowite
MethodHandles.lookup().lookupClass();
od Reina
Przygotowałem jmh punktem odniesienia dla wszystkich wariantów i wyników są:
Wnioski
Dostępne tylko od wersji Java 7 i Android API 26!
Jeśli potrzebujesz go w wielu miejscach i nie chcesz, aby twój kod bajtowy wzdychał z powodu mnóstwa anonimowych klas -
SecurityManager
jest twoim przyjacielem (trzecia najlepsza opcja).Ale nie możesz po prostu zadzwonić
getClassContext()
- jest chroniony wSecurityManager
klasie. Będziesz potrzebować klasy pomocniczej takiej jak ta:getStackTrace()
wyjątku lubThread.currentThread()
. Bardzo nieefektywny i może zwracać tylko nazwę klasy jako, aString
nieClass<*>
instancję.PS
Jeśli chcesz utworzyć instancję rejestratora dla statycznych narzędzi kotlin (takich jak ja :), możesz użyć tego pomocnika:
Przykład użycia:
źródło
Ta instrukcja działa dobrze:
źródło
Thread.getStackTrace()
, zobaczysz, że nie robi nic innego niżreturn (new Exception()).getStackTrace();
w przypadku wywołania wcurrentThread()
. Tak więc rozwiązanie @count ludwig jest bardziej bezpośrednim sposobem na osiągnięcie tego samego.Możesz zrobić coś naprawdę słodkiego, używając JNI w następujący sposób:
MyObject.java:
następnie:
następnie:
MyObject.c:
Następnie skompiluj C do wspólnej biblioteki o nazwie
libclassname.so
i uruchom java!*chichot
źródło
Java_MyObject_getClassName
ma osadzoną nazwę. Rozwiązaniem jest korzystanie z JNIRegisterNatives
. Oczywiście trzeba by to nakarmić JNIFindClass(env, 'com/example/MyObject')
, więc nie ma też wygranej.private static final String TAG = "MyClass"
alboprivate static final String TAG = MyClass.class.getSimpleName();
Drugi jest bardziej przyjazny dla globalnej zmiany nazw klas za pomocą IDE.Używam tego do inicjowania Log4j Logger na szczycie moich klas (lub adnotacji).
PRO: Throwable jest już załadowany i możesz zaoszczędzić zasoby, nie używając programu SecurityManager „IO heavy”.
CON: Pewne pytanie, czy to zadziała dla wszystkich JVM.
źródło
Nadużywaj SecurityManager
Lub, jeśli nie ustawione, użyj wewnętrznej klasy, która ją rozszerza (przykład poniżej wstydliwie skopiowany z How's Real ):
źródło
Jeśli chcesz z nim całą nazwę pakietu, zadzwoń:
Jeśli chcesz tylko ostatni element, wywołaj:
źródło
Dosłownie użycie klasy obiektu wywołującego tak jak
MyClass.class.getName()
faktycznie wykonuje to zadanie, ale jest podatne na błędy kopiowania / wklejania, jeśli propagujesz ten kod do wielu klas / podklas, w których potrzebujesz tej nazwy klasy.A przepis Toma Hawtina nie jest wcale taki zły, wystarczy go odpowiednio ugotować :)
Jeśli masz klasę bazową z metodą statyczną, która może być wywoływana z podklas, a ta metoda statyczna musi znać rzeczywistą klasę dzwoniącego, można to osiągnąć w następujący sposób:
źródło
Bezpieczne dla refaktoryzacji, bezpieczne dla cięcia i wklejania rozwiązanie, które pozwala uniknąć definicji klas ad-hoc poniżej.
Napisz metodę statyczną, która odzyskuje nazwę klasy, starając się zawrzeć nazwę klasy w nazwie metody:
następnie przywołaj to w metodzie statycznej:
Bezpieczeństwo refaktoryzacji jest zapewnione przez unikanie użycia ciągów, zapewnione jest bezpieczeństwo wycinania i wklejania, ponieważ jeśli wytniesz i wkleisz metodę wywołującą, nie znajdziesz funkcji getMyClassName () w docelowej klasie „MyClass2”, więc będziesz zmuszony ją przedefiniować i zaktualizować.
źródło
Ponieważ pytanie Coś w rodzaju „this.class` zamiast„ ClassName.class`? jest oznaczony jako duplikat tego (co jest dyskusyjne, ponieważ to pytanie dotyczy raczej klasy niż nazwy klasy), zamieszczam odpowiedź tutaj:
Ważne jest, aby zdefiniować
thisClass
jako prywatny, ponieważ:1) nie można go dziedziczyć: klasy pochodne muszą albo zdefiniować własne,
thisClass
albo wygenerować komunikat o błędzie2) należy odwoływać się do innych klas
ClassName.class
zamiastClassName.thisClass
.Po
thisClass
zdefiniowaniu dostęp do nazwy klasy staje się:źródło
Potrzebowałem nazwy klasy w metodach statycznych wielu klas, dlatego zaimplementowałem klasę JavaUtil za pomocą następującej metody:
Mam nadzieję, że to pomoże!
źródło
Użyłem te dwa podejścia do obu
static
inon static
scenariusz:Główna klasa:
Jak podać nazwę klasy:
sposób niestatyczny:
Sposób statyczny:
źródło
Jeśli używasz odbicia, możesz uzyskać obiekt Method, a następnie:
Aby uzyskać samą metodę, prawdopodobnie możesz użyć:
źródło
Class.forName("class name")
już klasę. Dlaczego chcesz go odzyskać metodą?