292

How can one get the name of the class from a static method in that class. For example

public class MyClass {
    public static String getClassName() {
        String name = ????; // what goes here so the string "MyClass" is returned
        return name;
    }
}

To put it in context, I actually want to return the class name as part of a message in an exception.

Miles D
  • 7,960
  • 5
  • 34
  • 35

15 Answers15

258

In order to support refactoring correctly (rename class), then you should use either:

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

or (thanks to @James Van Huis):

 MyClass.class.getSimpleName(); // class name and no more
Community
  • 1
  • 1
toolkit
  • 49,809
  • 17
  • 109
  • 135
  • 153
    If you're going to hard-code in knowledge of MyClass like that, then you might as well just do String name = "MyClass"; ! – John Topley Jun 01 '09 at 20:45
  • 118
    But then, refactoring the class name in your IDE will not work properly. – James Van Huis Jun 01 '09 at 20:48
  • 10
    True. Although MyClass.class will ensure this line doesn't get forgotten with a 'change class name' refactoring – toolkit Jun 01 '09 at 20:50
  • 22
    I *wish* "this" worked in a static context to mean the current Class in Java, that that "class.xxx" was allowed in either instance or static code to mean this class! The problem with this is that MyClass is verbose and redundant, in the context. But then as much as I like Java it does seem to lean towards verbosity. – Lawrence Dol Jun 02 '09 at 04:41
  • 57
    What if I'm calling the static method in a subclass, and I want the subclass name? – Edward Falk Oct 26 '12 at 15:49
  • 5
    @EdwardFalk That's exactly what I came here for too! Very sad it wasn't even addressed in the least. – JMTyler Apr 08 '13 at 22:25
  • 3
    Unfortunately, it seems to not be do-able. In essence, static methods aren't aware of the class hierarchy. – Edward Falk Apr 08 '13 at 23:49
  • @John This is very useful if you think you might change the package name, though. It will handle that sort of change (but nothing else). – GKFX Jul 19 '14 at 15:35
  • @EdwardFalk: Static methods are class level methods. It's your responsibility as a developer to keep that in mind. – Michaël Benjamin Saerens Apr 17 '15 at 12:05
  • This does not seem to work if you are using generics. I can't say MyClass.class.getName() for example. – BobDoolittle Feb 09 '16 at 21:04
  • Your simplicity does not allow an abstract routebuilder class in apache camel that "encapsulates" a static method getRouteId(){ return "direct:"+classname; }. – Blessed Geek Jul 04 '18 at 08:30
  • 2
    In PHP you can use "self" (instead of "this") in a static method. I wish Java had the same. – entreprenr May 14 '20 at 08:38
134

In Java 7+ you can do this in static method/fields:

MethodHandles.lookup().lookupClass()
Rein
  • 2,487
  • 1
  • 17
  • 9
  • I was gonna say `Reflection.getCallerClass()`. But it gives a warning about being in the 'sun' packages. So this might be a better solution. – Foumpie Dec 26 '15 at 22:55
  • 1
    @Foumpie: Java 9 is going to introduce an official API that will supersede this unofficial `Reflection.getCallerClass()` thing. It’s a bit complicated for his trivial operation, i.e. `Optional> myself = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map(StackWalker.StackFrame::getDeclaringClass) .findFirst());`, but of course, that’s connected to the fact that it will be much more powerful. – Holger Feb 07 '17 at 13:54
  • 7
    This is easily the best solution. It avoids the need to specify the actual class name, it's not obscure, it's not a hack and according to Artyom Krivolapov's post below it's also by far the fastest approach. – skomisa Jan 09 '18 at 05:25
  • 2
    @Rein Is there a way get the runtime class if this was called in the base class? – Glide Mar 21 '18 at 00:22
122

Do what @toolkit says. Do not do anything like this:

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

(Edit: Or if you are using a Java version that came out well after this answer was originally written, use @Rein's answer.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 7
    If the class extends another one, this doesn't return the actual class, only the base class. – Luis Soeiro Sep 12 '12 at 22:34
  • 1
    @LuisSoeiro I believe it returns the class that the method is defined in. I'm not sure how the base class factors into the static context. – Tom Hawtin - tackline Sep 13 '12 at 00:18
  • 8
    I do not understand why getClass() cannot be static. This "idiom" would then not be needed. – mmirwaldt Aug 14 '13 at 09:52
  • @mmirwaldt "idiom"? Well, I suppose there are methods to this madness :-/ – Navin Nov 03 '13 at 02:40
  • 1
    @mmirwaldt `getClass` returns the runtime type, so can't be static. – Tom Hawtin - tackline Nov 03 '13 at 12:54
  • 2
    If I got what @LuisSoeiro meant, this method only works if called from the class that defines it. Polymorphism will break. A subclass calling this same method will not obtain its own name, only parent name. Oh, that "new Throwable().getStackTrace()[0].getClassName()" method is nice and I would rather use it, BUT it will fail as well when used by a subclass. – PFROLIM Aug 21 '14 at 21:00
  • 5
    This is the real answer. Because you do not need to write the name of your class in your code yourself. – Bob Jan 03 '15 at 07:59
  • Why would you answer with "do not do anything like this"? This belongs in a comment not in an answer... – WattsInABox Dec 11 '18 at 15:36
  • @WattsInABox I think that's a highly irresponsible attitude. – Tom Hawtin - tackline Dec 11 '18 at 16:25
  • You didn’t answer the question, you explicitly answered what not to do. I guess you could link directly to the right answer instead of referencing a username... I disagree that I’m being “irresponsible”. I’m trying to be responsible to make sure answers are as high-quality as possible. – WattsInABox Dec 11 '18 at 16:28
94

So, we have a situation when we need to statically get class object or a class full/simple name without an explicit usage of MyClass.class syntax.

It can be really handy in some cases, e.g. logger instance for the upper-level functions (in this case kotlin creates a static Java class not accessible from the kotlin code).

We have a few different variants for getting this info:

  1. new Object(){}.getClass().getEnclosingClass();
    noted by Tom Hawtin - tackline

  2. getClassContext()[0].getName(); from the SecurityManager
    noted by Christoffer

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

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

  5. and finally awesome

    MethodHandles.lookup().lookupClass();
    from Rein


I've prepared a benchmark for all variants and results are:
# 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

Conclusions

  1. Best variant to use, rather clean and monstrously fast.
    Available only since Java 7 and Android API 26!
 MethodHandles.lookup().lookupClass();
  1. In case you need this functionality for Android or Java 6, you can use the second best variant. It's rather fast too, but creates an anonymous class in each place of usage :(
 new Object(){}.getClass().getEnclosingClass();
  1. If you need it in many places and don't want your bytecode to bloat due to tons of anonymous classes – SecurityManager is your friend (third best option).

But you can't just call getClassContext() – it's protected in the SecurityManager class. You will need some helper class like this:

 // 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. You probably don't ever need to use last two variants based on the getStackTrace() from exception or the Thread.currentThread(). Very inefficient and can return only the class name as a String, not the Class<*> instance.

P.S.

If you want to create a logger instance for static kotlin utils (like me :), you can use this 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())

Usage example:

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
 * @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
}
Artyom Krivolapov
  • 3,161
  • 26
  • 32
43

This instruction works fine:

Thread.currentThread().getStackTrace()[1].getClassName();
bluish
  • 26,356
  • 27
  • 122
  • 180
Keksi
  • 447
  • 4
  • 2
  • 5
    Take care, that it can be really slow. However you can copy paste it. – Gábor Lipták Nov 12 '12 at 13:12
  • 1
    This has the added benefit of not having to create an Object or a Thread each time you use it. – Erel Segal-Halevi Jan 01 '13 at 12:46
  • 5
    @ErelSegalHalevi It creates a whole lot of [StackTraceElement](http://docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html)s in the background though :( – Navin Nov 03 '13 at 02:43
  • 4
    If you look at the source code of `Thread.getStackTrace()` you'll see that it does nothing else than `return (new Exception()).getStackTrace();` in the case of being called on the `currentThread()`. So the solution of @count ludwig is the more direct way to achieve the same. – T-Bull Nov 16 '13 at 13:44
35

You could do something really sweet by using JNI like this:

MyObject.java:

public class MyObject
{
    static
    {
        System.loadLibrary( "classname" );
    }

    public static native String getClassName();

    public static void main( String[] args )
    {
        System.out.println( getClassName() );
    }
}

then:

javac MyObject.java
javah -jni MyObject

then:

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 );
}

Then compile the C up into a shared library called libclassname.so and run the java!

*chuckle

lifelongcoug
  • 678
  • 6
  • 12
  • Why is this not built in? – ggb667 Apr 03 '14 at 20:39
  • Clever, and I appreciate the humor. The fly in the ointment is that the default name of the C function `Java_MyObject_getClassName` has the name embedded. The way around that is to use the JNI `RegisterNatives`. Of course you'd have to feed that with the JNI `FindClass(env, 'com/example/MyObject')`, so no win there either. – Renate Nov 29 '14 at 12:36
  • 2
    @Renate, so this whole answer is actually a joke? If so, please make it very explicit because you know, we are supposed to help other people, so let's not push innocents into traps. – Stéphane Gourichon Jun 09 '16 at 14:46
  • Well, it wasn't my joke and I pointed out that it was a joke. The use case for this scenario is usually for identify the class in logs. Stripping away all the complexity, it usually boils down to doing either: `private static final String TAG = "MyClass"` or `private static final String TAG = MyClass.class.getSimpleName();` The second is more friendly for global class renaming using an IDE. – Renate Jun 30 '16 at 11:30
21

I use this to init the Log4j Logger at the top of my classes (or annotate).

PRO: Throwable is already loaded and you might save resources by not using the "IO heavy" SecurityManager.

CON: Some question as to whether this will work for all JVMs.

// 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()); 
bluish
  • 26,356
  • 27
  • 122
  • 180
count ludwig
  • 227
  • 2
  • 2
  • Create your own exception class so the jvm wont bother: http://jhocr.googlecode.com/svn/trunk/src/main/java/com/googlecode/jhocr/util/LoggUtilException.java – 4F2E4A2E Dec 17 '13 at 21:46
  • 1
    If you are going to suggest something as awful as this solution, please at least relate your pros to the natural solution of using MyClass.class.getName(), instead of another horrible solution like abusing the SecurityManager. – Søren Boisen May 30 '15 at 19:58
  • More cons: too verbose; slow (this is actually a minor point because it runs only once, when the class is loaded). – toolforger Nov 28 '17 at 12:37
14

Abuse the SecurityManager

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

Or, if not set, use an inner class that extends it (example below shamefully copied from Real's HowTo):

public static class CurrentClassGetter extends SecurityManager {
    public String getClassName() {
        return getClassContext()[1].getName(); 
    }
}
Christoffer
  • 12,712
  • 7
  • 37
  • 53
9

If you want the entire package name with it, call:

String name = MyClass.class.getCanonicalName();

If you only want the last element, call:

String name = MyClass.class.getSimpleName();
James Van Huis
  • 5,481
  • 1
  • 26
  • 25
7

Verbatim use of caller's class like MyClass.class.getName() actually does the job, but is prone to copy/paste errors if you propagate this code to numerous classes/subclasses where you need this class name.

And Tom Hawtin's recipe is in fact not bad, one just needs to cook it the right way :)

In case you have a base class with a static method that may be called from subclasses, and this static method needs to know the actual caller's class, this may be achieved like the following:

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);
  }
}
Community
  • 1
  • 1
Sergey Ushakov
  • 2,425
  • 1
  • 24
  • 15
4

A refactoring-safe, cut&paste-safe solution that avoids the definition of ad-hoc classes below.

Write a static method that recover the class name having care to include the class name in the method name:

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

then recall it in your static method:

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

Refactoring safety is given by avoiding the use of strings, cut&paste safety is granted because if you cut&paste the caller method you won't find the getMyClassName() in the target "MyClass2" class, so you will be forced to redefine and update it.

avalori
  • 427
  • 2
  • 5
  • 17
4

Since the question Something like `this.class` instead of `ClassName.class`? is marked as a duplicate for this one (which is arguable because that question is about the class rather than class name), I'm posting the answer here:

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);
    }
}

It is important to define thisClass as private because:
1) it must not be inherited: derived classes must either define their own thisClass or produce an error message
2) references from other classes should be done as ClassName.class rather than ClassName.thisClass.

With thisClass defined, access to the class name becomes:

thisClass.getName()
Community
  • 1
  • 1
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
1

I needed the class name in the static methods of multiple classes so I implemented a JavaUtil Class with the following method :

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

Hope it will help !

phaderer
  • 11
  • 1
  • 1
    Not only is it bad to use this because of the magic number 2(that could easily result in a NullPointerException), but you are heavily relying on the accuracy of the virtual machine. From the method's javadoc : * Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this thread is permitted to return a zero-length array from this method. * – Shotgun Jun 10 '15 at 13:43
0

I have used these two approach for both static and non static scenario:

Main class:

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

//For static approach
public AndroidLogger(String className) {
    mClassName = className;
}

How to provide class name:

non static way:

private AndroidLogger mLogger = new AndroidLogger(this);

Static way:

private static AndroidLogger mLogger = new AndroidLogger(Myclass.class.getSimpleName());
0xAliHn
  • 18,390
  • 23
  • 91
  • 111
-2

If you are using reflection, you can get the Method object and then:

method.getDeclaringClass().getName()

To get the Method itself, you can probably use:

Class<?> c = Class.forName("class name");
Method  method = c.getDeclaredMethod ("method name", parameterTypes)
Franzé Jr.
  • 1,194
  • 13
  • 20