¿Cómo se puede obtener el nombre de la clase a partir de un método estático en la 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, de hecho, me quieren 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();}
InformationsquelleAutor Miles D | 2009-06-01

15 Comentarios

  1. 219

    Con el fin de apoyar la refactorización correctamente (cambiar el nombre de la clase), entonces usted debe utilizar:

     MyClass.class.getName(); //full name with package

    o (gracias a @James Van Huis):

     MyClass.class.getSimpleName(); //class name and no more
    • Si usted va a codificar en el conocimiento de Miclase, entonces usted puede ser que también acaba de hacer String name = «Miclase»; !
    • Pero entonces, la refactorización el nombre de la clase en el IDE no funcionará correctamente.
    • Verdadero. Aunque MyClass.class se asegurará de que esta línea no se olvidan con un ‘cambio de clase’ nombre de la refactorización
    • Yo deseo «este» trabajaba en un contexto estático, que significa la actual Clase en Java, que «de la clase.xxx» fue permitido en cualquier instancia o de código estático para la media de esta clase! El problema con esto es que Miclase es detallado y redundante, en el contexto. Pero entonces, como mucho, como me gusta Java parece inclinarse hacia la verbosidad.
    • Lo que si estoy llamando al método estático en una subclase, y quiero que la subclase nombre?
    • Eso es exactamente lo que yo he venido aquí para también! Muy triste, aunque no fue abordado en el menos.
    • Por desgracia, parece no ser capaz de hacer -. En esencia, los métodos estáticos no son conscientes de la jerarquía de clases.
    • Esto es muy útil si usted piensa que usted puede cambiar el nombre del paquete, sin embargo. Va a manejar ese tipo de cambio (pero nada más).
    • Los métodos estáticos son de la clase los métodos de nivel. Es tu responsabilidad como un desarrollador que tener eso en mente.
    • Al parecer esto no funciona si el uso de medicamentos genéricos. No puedo decir Miclase<T>.clase.getName() por ejemplo.
    • Su sencillez no permiten un resumen routebuilder clase en apache camel que «encapsula» un método estático getRouteId(){ return «directa:»+nombre de la clase; }.

  2. 117

    Hacer lo toolkit dice. No hacer algo como esto:

    return new Object() { }.getClass().getEnclosingClass();
    • esto parece menos mala que la de SecurityManager o Arrojar soluciones…
    • Si la clase se extiende a otro, esto no devuelvan los reales de la clase, sólo la clase base.
    • Creo que devuelve la clase que se define el método en. No estoy seguro de cómo la clase base de los factores en el contexto estático.
    • Yo no entiendo por qué getClass() no puede ser estático. Este «lenguaje» no sería entonces necesario.
    • Bueno, supongo que hay métodos para esta locura :-/
    • devuelve el tipo en tiempo de ejecución, por lo que no puede ser estático.
    • Si yo tengo lo @LuisSoeiro significaba, este método sólo funciona si se llama desde la clase que lo define. El polimorfismo se va a romper. Una subclase de llamar a este método no va a obtener su propio nombre, sólo el nombre del padre. Oh, que el «nuevo Arrojadiza().getStackTrace()[0].getClassName()» el método es bueno y prefiero usarlo, PERO fallan cuando se utiliza por una subclase.
    • Esta es la verdadera respuesta. Ya que no es necesario escribir el nombre de su clase en el código.
    • Por qué tendrían que responder con «no hacer nada de esto»? Esto pertenece en un comentario no una respuesta…
    • Creo que es una muy irresponsable actitud.
    • No has contestado a la pregunta, usted explícitamente respondió qué no hacer. Supongo que se podría vincular directamente a la respuesta correcta en lugar de hacer referencia a un nombre de usuario… no estoy de acuerdo que estoy siendo «irresponsable». Yo estoy tratando de ser responsable para asegurarse de que las respuestas son de alta calidad como sea posible.
    • También podría explicar por qué la gente no debería hacer esto…

  3. 81

    En Java 7+ usted puede hacer esto en el método estático/campos:

    MethodHandles.lookup().lookupClass()
    • Iba a decir Reflection.getCallerClass(). Pero da una advertencia acerca de estar en el ‘sol’ de los paquetes. Así que esta podría ser una mejor solución.
    • Java 9 se va a introducir un oficial de la API que sustituirá a este no oficial Reflection.getCallerClass() cosa. Es un poco complicado para su operación trivial, es decir,Optional<Class<?>> myself = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map(StackWalker.StackFrame::getDeclaringClass) .findFirst());, pero, por supuesto, que está conectado con el hecho de que va a ser mucho más potente.
    • Esta es sin duda la mejor solución. Evita la necesidad de especificar el nombre de clase real, no es oscuro, no es un hack y de acuerdo a Artyom Krivolapov del post de abajo también es por lejos el más rápido enfoque.
    • Hay una manera de obtener la clase en tiempo de ejecución si esto fue llamado en la clase base?
    • Esto debe ser aceptado respuesta
    • Esto no funciona correctamente si en una clase base.

  4. 41

    Por lo tanto, tenemos una situación en la que necesitamos de forma estática obtener el objeto de la clase o de una clase completa/nombre simple sin una explícita el uso de MyClass.class sintaxis.

    Puede ser muy útil en algunos casos, por ejemplo, registrador instancia por el

    Tenemos un par de variantes diferentes para obtener esta información:

    1. new Object(){}.getClass().getEnclosingClass();

      señaló Tom Hawtin – tackline

    2. getClassContext()[0].getName(); de la SecurityManager

      señaló Christoffer

    3. new Throwable().getStackTrace()[0].getClassName();

      por el conde ludwig

    4. Thread.currentThread().getStackTrace()[1].getClassName();

      de Keksi

    5. y finalmente impresionante

      MethodHandles.lookup().lookupClass();

      de Rein


    He preparado un punto de referencia para todas las variantes y los resultados son:

    # Run complete. Total time: 00:04:18
    
    Benchmark                                                      Mode  Cnt      Score     Error  Units
    StaticClassLookup.MethodHandles_lookup_lookupClass             avgt   30      3.630 ±   0.024  ns/op
    StaticClassLookup.AnonymousObject_getClass_enclosingClass      avgt   30    282.486 ±   1.980  ns/op
    StaticClassLookup.SecurityManager_classContext_1               avgt   30    680.385 ±  21.665  ns/op
    StaticClassLookup.Thread_currentThread_stackTrace_1_className  avgt   30  11179.460 ± 286.293  ns/op
    StaticClassLookup.Throwable_stackTrace_0_className             avgt   30  10221.209 ± 176.847  ns/op

    Conclusiones

    1. Mejor variante para el uso, en lugar limpio y monstruosamente rápido.

      Disponible sólo a partir de Java 7 y Android API 26!
     MethodHandles.lookup().lookupClass();
    1. En caso de que usted necesita esta funcionalidad para Android o Java 6, puede utilizar el segundo mejor variante. Es bastante rápido también, sino que crea una clase anónima en cada lugar de uso 🙁
     new Object(){}.getClass().getEnclosingClass();
    1. Si usted lo necesita en muchos lugares y no quiere que su bytecode a la hinchazón debido a las toneladas de las clases anónimas – SecurityManager es tu amigo (la tercera mejor opción).

      Pero no se puede llamar getClassContext() – es protegido en el SecurityManager clase. Usted necesitará un poco de ayudante de clase como esta:

     //Helper class
     public final class CallerClassGetter extends SecurityManager
     {
        private static final CallerClassGetter INSTANCE = new CallerClassGetter();
        private CallerClassGetter() {}
    
        public static Class<?> getCallerClass() {
            return INSTANCE.getClassContext()[1];
        }
     }
    
     //Usage example:
     class FooBar
     {
        static final Logger LOGGER = LoggerFactory.getLogger(CallerClassGetter.getCallerClass())
     }
    1. Usted probablemente no necesite utilizar dos últimas variantes basadas en el getStackTrace() de excepción o de la Thread.currentThread(). Muy ineficiente y puede devolver sólo el nombre de la clase como un String, no la Class<*> instancia.

    P. S.

    Si quieres crear un registrador de instancia para la estática kotlin utils (como yo :), usted puede utilizar este helper:

    import org.slf4j.Logger
    import org.slf4j.LoggerFactory
    
    //Should be inlined to get an actual class instead of the one where this helper declared
    //Will work only since Java 7 and Android API 26!
    @Suppress("NOTHING_TO_INLINE")
    inline fun loggerFactoryStatic(): Logger
        = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass())

    Ejemplo de uso:

    private val LOGGER = loggerFactoryStatic()
    
    /**
     * Returns a pseudo-random, uniformly distributed value between the
     * given least value (inclusive) and bound (exclusive).
     *
     * @param min the least value returned
     * @param max the upper bound (exclusive)
     *
     * @return the next value
     * @throws IllegalArgumentException if least greater than or equal to bound
     * @see java.util.concurrent.ThreadLocalRandom.nextDouble(double, double)
     */
    fun Random.nextDouble(min: Double = .0, max: Double = 1.0): Double {
        if (min >= max) {
            if (min == max) return max
            LOGGER.warn("nextDouble: min $min > max $max")
            return min
        }
        return nextDouble() * (max - min) + min
    }
  5. 38

    Esta instrucción funciona bien:

    Thread.currentThread().getStackTrace()[1].getClassName();
    • Ten cuidado, que puede ser muy lento. Sin embargo, usted puede copiar y pegar la misma.
    • Esto tiene el beneficio añadido de no tener que crear un Objeto o un Hilo cada vez que la utilice.
    • Se crea una gran cantidad de StackTraceElements en el fondo, aunque 🙁
    • Si miramos el código fuente de Thread.getStackTrace() vas a ver que no hace nada más que return (new Exception()).getStackTrace(); en el caso de que se llama en la currentThread(). Así, la solución de @conde ludwig es la manera más directa para lograr el mismo.
  6. 34

    Se podría hacer algo realmente dulce mediante JNI como este:

    MyObject.java:

    public class MyObject
    {
        static
        {
            System.loadLibrary( "classname" );
        }
    
        public static native String getClassName();
    
        public static void main( String[] args )
        {
            System.out.println( getClassName() );
        }
    }

    a continuación:

    javac MyObject.java
    javah -jni MyObject

    a continuación:

    MyObject.c:

    #include "MyObject.h"
    
    JNIEXPORT jstring JNICALL Java_MyObject_getClassName( JNIEnv *env, jclass cls )
    {
        jclass javaLangClass = (*env)->FindClass( env, "java/lang/Class" );
        jmethodID getName = (*env)->GetMethodID( env, javaLangClass, "getName",
            "()Ljava/lang/String;" );
        return (*env)->CallObjectMethod( env, cls, getName );
    }

    A continuación, compile el C en una biblioteca compartida llamado libclassname.so y ejecutar java!

    *risa

    • ¿Por qué no es incorporada?
    • Inteligente, y aprecio el humor. La mosca en el ungüento es que el nombre predeterminado de la función de C Java_MyObject_getClassName tiene el nombre incrustado. La forma de hacerlo es utilizar la JNI RegisterNatives. Por supuesto, usted tendría que alimentar con la JNI FindClass(env, 'com/example/MyObject'), por lo que de no ganar allí.
    • así que toda respuesta es en realidad una broma? Si es así, por favor, que sea muy explícito, porque usted sabe, se supone que vamos a ayudar a otras personas, así que no empuje inocentes en las trampas.
    • Bien, no era mi broma y me señaló que era una broma. El caso de uso para este escenario es por lo general para identificar la clase de registros. Quitando toda la complejidad, que generalmente se reduce a una: private static final String TAG = "MyClass" o private static final String TAG = MyClass.class.getSimpleName(); La segunda es más amigable para el mundial de la clase de cambiar el nombre utilizando un IDE.
  7. 20

    Yo uso este para init el Log4j Registrador en la parte superior de mis clases (o anotación).

    PRO: Arrojadiza ya está cargado y usted podría ahorrar recursos, por no utilizar el «IO pesado» SecurityManager.

    CON: Algunas dudas sobre si esto va a funcionar para todos los Jvm.

    //Log4j . Logger --- Get class name in static context by creating an anonymous Throwable and 
    //getting the top of its stack-trace. 
    //NOTE you must use: getClassName() because getClass() just returns StackTraceElement.class 
    static final Logger logger = Logger.getLogger(new Throwable() .getStackTrace()[0].getClassName()); 
    • Crear su propia clase de excepción para la jvm no molestar: jhocr.googlecode.com/svn/trunk/src/main/java/com/googlecode/…
    • Si usted va a sugerir algo tan horrible como esta solución, por favor, al menos, se refieren a sus profesionales para la solución natural de la utilización de Miclase.clase.getName(), en lugar de otro horrible solución de abusar de la SecurityManager.
    • Más contras: demasiado detallado; lento (esto es realmente una cuestión menor, ya que se ejecuta sólo una vez, cuando se carga la clase).
  8. 13

    Abuso de la SecurityManager

    System.getSecurityManager().getClassContext()[0].getName();

    O, si no se establece el uso de una clase interna que se extiende (por ejemplo por debajo de vergonzosamente copiado de Real HowTo):

    public static class CurrentClassGetter extends SecurityManager {
        public String getClassName() {
            return getClassContext()[1].getName(); 
        }
    }
  9. 9

    Si quieres el nombre completo del paquete con él, llame al:

    String name = MyClass.class.getCanonicalName();

    Si desea que sólo el último elemento, llame al:

    String name = MyClass.class.getSimpleName();
  10. 5

    Verbatim uso de la llamada clase como MyClass.class.getName() en realidad hace el trabajo, pero es propenso a copiar/pegar de errores si propagar este código a numerosas clases/subclases donde se necesita el nombre de la clase.

    Y Tom Hawtin receta es, de hecho, no es malo, sólo se debe cocinar de la forma correcta 🙂

    En caso de tener una clase base con un método estático que puede ser llamado desde subclases, y este método estático debe saber el real en el llamador de la clase, esto puede ser logrado como el siguiente:

    class BaseClass {
      static sharedStaticMethod (String callerClassName, Object... otherArgs) {
        useCallerClassNameAsYouWish (callerClassName);
        //and direct use of 'new Object() { }.getClass().getEnclosingClass().getName()'
        //instead of 'callerClassName' is not going to help here,
        //as it returns "BaseClass"
      }
    }
    
    class SubClass1 extends BaseClass {
      static someSubclassStaticMethod () {
        //this call of the shared method is prone to copy/paste errors
        sharedStaticMethod (SubClass1.class.getName(),
                            other_arguments);
        //and this call is safe to copy/paste
        sharedStaticMethod (new Object() { }.getClass().getEnclosingClass().getName(),
                            other_arguments);
      }
    }
  11. 4

    Una refactorización-segura, de corte&paste-solución segura que evita la definición de ad-hoc clases de abajo.

    Escribir un método estático que recuperar el nombre de la clase teniendo cuidado de incluir el nombre de la clase en el nombre del método:

    private static String getMyClassName(){
      return MyClass.class.getName();
    }

    luego de recordar que en su método estático:

    public static void myMethod(){
      Tracer.debug(getMyClassName(), "message");
    }

    Refactorización de seguridad es dada por el hecho de evitar el uso de cadenas, de corte&paste de seguridad se concede porque si usted cut&pegar la persona que llama método no encontrar el getMyClassName() en el destino «Miclase2» de la clase, por lo que se ven obligados a redefinir y actualizar.

  12. 3

    Ya que la pregunta Algo así como `this.class` en lugar de `ClassName.class`? está marcado como un duplicado de este (que es discutible debido a que la pregunta es acerca de la clase en lugar de el nombre de la clase), voy a postear la respuesta aquí:

    class MyService {
        private static Class thisClass = MyService.class;
        //or:
        //private static Class thisClass = new Object() { }.getClass().getEnclosingClass();
        ...
        static void startService(Context context) {
            Intent i = new Intent(context, thisClass);
            context.startService(i);
        }
    }

    Es importante definir thisClass como privado porque:

    1) no debe ser heredado: las clases derivadas deben definir sus propias thisClass o producir un mensaje de error

    2) las referencias de otras clases se debe hacer como ClassName.class en lugar de ClassName.thisClass.

    Con thisClass definido, el acceso al nombre de la clase se convierte en:

    thisClass.getName()
  13. 1

    Necesitaba el nombre de la clase en los métodos estáticos de varias clases de por lo que he implementado un JavaUtil Clase con el siguiente método :

    public static String getClassName() {
        String className = Thread.currentThread().getStackTrace()[2].getClassName();
        int lastIndex = className.lastIndexOf('.');
        return className.substring(lastIndex + 1);
    }

    Espero que sirvan de ayuda !

    • No sólo es malo para el uso de este porque la magia número 2(que fácilmente podría resultar en un NullPointerException), pero puede depender en gran medida de la precisión de la máquina virtual. A partir del método de javadoc : * Algunas máquinas virtuales pueden, en algunas circunstancias, omitir uno o más marcos de pila de la traza de la pila. En el caso extremo, una máquina virtual que no tiene seguimiento de la pila de la información relativa a este hilo que permite devolver una matriz de longitud cero de este método. *
  14. 0

    He utilizado estos dos enfoque, tanto static y non static escenario:

    Clase principal:

    //For non static approach
    public AndroidLogger(Object classObject) {
        mClassName = classObject.getClass().getSimpleName();
    }
    
    //For static approach
    public AndroidLogger(String className) {
        mClassName = className;
    }

    Cómo proporcionar el nombre de la clase:

    no de manera estática:

    private AndroidLogger mLogger = new AndroidLogger(this);

    Manera estática:

    private static AndroidLogger mLogger = new AndroidLogger(Myclass.class.getSimpleName());
  15. -1

    Si usted está utilizando la reflexión, usted puede conseguir el Método de objeto y, a continuación:

    method.getDeclaringClass().getName()

    Para obtener el Método en sí, usted probablemente puede utilizar:

    Class<?> c = Class.forName("class name");
    Method  method = c.getDeclaredMethod ("method name", parameterTypes)
    • Y ¿cómo sabrás qué es: «nombre de la clase» ? 🙂
    • Tener Class.forName("class name") ya dar una clase. ¿Por qué quieres recuperar a través de Método?

Dejar respuesta

Please enter your comment!
Please enter your name here