¿Cómo se puede obtener el nombre de la clase de un método estático en esa clase? Por ejemplo
public class MyClass {
public static String getClassName() {
String name = ????; // what goes here so the string "MyClass" is returned
return name;
}
}
Para ponerlo en contexto, en realidad quiero devolver el nombre de la clase como parte de un mensaje en una excepción.
try{ throw new RuntimeEsception();} catch(RuntimeEcxeption e){return e.getstackTrace()[1].getClassName();
}Respuestas:
Para admitir la refactorización correctamente (cambiar el nombre de la clase), debe usar:
o (gracias a @James Van Huis ):
fuente
Haz lo que dice el juego de herramientas. No hagas nada como esto:
fuente
getClass
devuelve el tipo de tiempo de ejecución, por lo que no puede ser estático.En Java 7+ puede hacer esto en métodos / campos estáticos:
fuente
Reflection.getCallerClass()
. Pero da una advertencia sobre estar en los paquetes 'sol'. Entonces esta podría ser una mejor solución.Reflection.getCallerClass()
cosa no oficial . Es un poco complicado para su operación trivial, es decirOptional<Class<?>> myself = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map(StackWalker.StackFrame::getDeclaringClass) .findFirst());
, pero por supuesto, eso está relacionado con el hecho de que será mucho más poderoso.Entonces, tenemos una situación en la que necesitamos obtener estáticamente un objeto de clase o un nombre completo / simple de clase sin un uso explícito de
MyClass.class
sintaxis.Puede ser realmente útil en algunos casos, por ejemplo, la instancia del registrador para Kotlin funciones de nivel superior (en este caso, kotlin crea una clase Java estática no accesible desde el código de kotlin).
Tenemos algunas variantes diferentes para obtener esta información:
new Object(){}.getClass().getEnclosingClass();
señalado por Tom Hawtin - tackline
getClassContext()[0].getName();
de loSecurityManager
señalado por Christoffer
new Throwable().getStackTrace()[0].getClassName();
por el conde ludwig
Thread.currentThread().getStackTrace()[1].getClassName();
de Keksi
y finalmente impresionante
MethodHandles.lookup().lookupClass();
de Rein
He preparado un jmh Los puntos de referencia para todas las variantes y resultados son:
Conclusiones
¡Disponible solo desde Java 7 y Android API 26!
Si lo necesita en muchos lugares y no quiere que su código de bytes se hinche debido a toneladas de clases anónimas,
SecurityManager
es su amigo (la tercera mejor opción).Pero no puedes simplemente llamar
getClassContext()
, está protegido en laSecurityManager
clase. Necesitarás una clase auxiliar como esta:getStackTrace()
excepción from o deThread.currentThread()
. Muy ineficiente y puede devolver solo el nombre de la clase como aString
, no laClass<*>
instancia.PD
Si desea crear una instancia de registrador para utilidades estáticas de kotlin (como yo :), puede usar este ayudante:
Ejemplo de uso:
fuente
Esta instrucción funciona bien:
fuente
Thread.getStackTrace()
, verás que no hace nada más quereturn (new Exception()).getStackTrace();
en el caso de ser llamado en elcurrentThread()
. Entonces, la solución de @count ludwig es la forma más directa de lograr lo mismo.Podrías hacer algo realmente dulce usando JNI como este:
MyObject.java:
luego:
luego:
MyObject.c:
Luego compile el C en una biblioteca compartida llamada
libclassname.so
y ejecute Java.*risita
fuente
Java_MyObject_getClassName
tiene el nombre incrustado. La forma de evitar eso es usar el JNIRegisterNatives
. Por supuesto, tendrías que alimentar eso con el JNIFindClass(env, 'com/example/MyObject')
, así que tampoco ganarás allí.private static final String TAG = "MyClass"
oprivate static final String TAG = MyClass.class.getSimpleName();
El segundo es más amigable para el cambio de nombre de clase global usando un IDE.Lo uso para iniciar el Log4j Logger en la parte superior de mis clases (o anotar).
PRO: Throwable ya está cargado y puede ahorrar recursos al no usar el SecurityManager "IO heavy".
CON: Algunas preguntas sobre si esto funcionará para todas las JVM.
fuente
Abusar del SecurityManager
O, si no está configurado, use una clase interna que lo extienda (ejemplo a continuación, copiado vergonzosamente de Real's HowTo ):
fuente
Si desea el nombre completo del paquete, llame al:
Si solo desea el último elemento, llame a:
fuente
El uso literal de la clase de la persona que llama como
MyClass.class.getName()
realmente hace el trabajo, pero es propenso a copiar / pegar errores si propaga este código a numerosas clases / subclases donde necesita este nombre de clase.Y la receta de Tom Hawtin, de hecho, no está mal, solo hay que cocinarla de la manera correcta :)
En caso de que tenga una clase base con un método estático al que se pueda llamar desde subclases, y este método estático necesita conocer la clase real del llamante, esto se puede lograr de la siguiente manera:
fuente
Una solución segura para refactorizar, cortar y pegar que evita la definición de clases ad-hoc a continuación.
Escriba un método estático que recupere el nombre de la clase teniendo cuidado de incluir el nombre de la clase en el nombre del método:
luego recuérdalo en tu método estático:
La seguridad de refactorización se proporciona evitando el uso de cadenas, se garantiza la seguridad de cortar y pegar porque si corta y pega el método de llamada no encontrará el getMyClassName () en la clase de destino "MyClass2", por lo que se verá obligado a redefinirlo y actualizarlo.
fuente
¿Desde la pregunta Algo como `this.class` en lugar de` ClassName.class`? está marcado como un duplicado para este (lo cual es discutible porque esa pregunta es sobre la clase en lugar del nombre de la clase), estoy publicando la respuesta aquí:
Es importante definirlo
thisClass
como privado porque:1) no debe heredarse: las clases derivadas deben definir las suyas propias
thisClass
o generar un mensaje de error2) las referencias de otras clases deben hacerse en
ClassName.class
lugar de hacerloClassName.thisClass
.Con
thisClass
definido, el acceso al nombre de la clase se convierte en:fuente
Necesitaba el nombre de la clase en los métodos estáticos de varias clases, así que implementé una clase JavaUtil con el siguiente método:
¡Espero que ayude!
fuente
He usado estos dos enfoques para ambos
static
ynon static
escenario:Clase principal:
Cómo proporcionar el nombre de la clase:
forma no estática:
Manera estática:
fuente
Si está utilizando la reflexión, puede obtener el objeto Método y luego:
Para obtener el Método en sí, probablemente pueda usar:
fuente
Class.forName("class name")
darte una clase. ¿Por qué quieres recuperarlo a través de Method?