Getting the class name from a static method in Java

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

MethodHandles.lookup().lookupClass()

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.)


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 kotlin 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 jmh 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
}

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

Tags:

Java

Static