Java getting static class name

How to call getClass() from a static method in Java?

I have a class that must have some static methods. Inside these static methods I need to call the method getClass() to make the following call:

public static void startMusic()
Cannot make a static reference to the non-static method getClass() from the type Object 

Using getResource() before there is an instance of a user defined (e.g. non-J2SE) class will sometimes fail. The problem is that the JRE will be using the bootstrap class-loader at that stage, which will not have application resources on the class-path (of the bootstrap loader).

9 Answers 9

The Answer

Just use TheClassName.class instead of getClass() .

Declaring Loggers

Since this gets so much attention for a specific usecase—to provide an easy way to insert log declarations—I thought I’d add my thoughts on that. Log frameworks often expect the log to be constrained to a certain context, say a fully-qualified class name. So they are not copy-pastable without modification. Suggestions for paste-safe log declarations are provided in other answers, but they have downsides such as inflating bytecode or adding runtime introspection. I don’t recommend these. Copy-paste is an editor concern, so an editor solution is most appropriate.

In IntelliJ, I recommend adding a Live Template:

  • Use «log» as the abbreviation
  • Use private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger($CLASS$.class); as the template text.
  • Click Edit Variables and add CLASS using the expression className()
  • Check the boxes to reformat and shorten FQ names.
  • Change the context to Java: declaration.
Читайте также:  Михаил Максимов — преподаватель информатики

Now if you type log it’ll automatically expand to

private static final Logger logger = LoggerFactory.getLogger(ClassName.class); 

And automatically reformat and optimize the imports for you.

Источник

Is it possible to get the class name from a static method? [duplicate]

When you are inside of a static method, is there a way to get the class name (a string containing the name) without typing the class name itself? For example, typing MyClass.class.getName() is no more useful than just «Myclass» .

A static method is associated only with the class that it is declared in. It seems to me that there isn’t a need to have a way of accessing the class other than explicitly referencing it by name.

3 Answers 3

You can use an anonymous inner class:

class Test < public static void main(String[] args) < String className = new Object()<>.getClass().getEnclosingClass().getName(); System.out.println(className); > > 

You can do it by creating (not throwing) a new Exception and inspecting its stack trace. Your class will be the zeroth element as it is the origin of the Exception. It kinda feels wrong, but it will work.

System.out.println( new Exception().getStackTrace()[0].getClassName() ); 

You can do the same with the Thread class. This seems cleaner to me, but the line is slightly longer. Your class is now the first element in the stacktrace rather than the zeroth. Thread.getStackTrace() is the zeroth.

System.out.println( Thread.currentThread().getStackTrace()[1].getClassName() ); 

For example, typing MyClass.class.getName() is no more useful than just «Myclass».

On the contrary, if you rename MyClass using your IDE’s refactor function it will replace MyClass.class.getName() with RenamedClass.class.getName(). If you put a string in there you’ll have to do it manually.

Источник

Getting the class name from a static method in Java

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

 MyClass.class.getName(); // full name with package 
 MyClass.class.getSimpleName(); // class name and no more 

If you’re going to hard-code in knowledge of MyClass like that, then you might as well just do String name = «MyClass»; !

True. Although MyClass.class will ensure this line doesn’t get forgotten with a ‘change class name’ refactoring

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.

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

MethodHandles.lookup().lookupClass() 

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

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.

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

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

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.

This is the real answer. Because you do not need to write the name of your class in your code yourself.

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
# 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
  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()) 
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 > 

Источник

java get accessing class name of static method

Is it possible to compute name of class which was used to access static method? To better understand question:

class S < public static String method() < return "S";// TODO compute class name here >> class S1 extends S < >class S2 extends S < >public class Main < public static void main(String[] args) < System.out.println(S.method()); //should print S System.out.println(S1.method()); //should print S1 System.out.println(S2.method()); //should print S2 >> 

Do you really want this or do you try to solve a different issue with this? What is your purpose for this feature?

In reality I have enum S1 and enum S2 and I want to store as much code as possible into interface S. To overcome imperfections of java enums I need to do it. The other solution is to use non-static default method but then I send to method not only class name but also irrelevant enum instance.

And why do you have two different enums when they are that similar? Maybe it isn’t a good idea to use enums if you have trouble with them?

3 Answers 3

You cannot do this, because neither S1.method nor S2.method exist in bytecode. The only method that is available for invocation is S.method . Compiler resolves all three calls to it, and produces identical invokestatic byte code for all three calls in your example.

The question doesn’t really make sense — calling method() will print S in each case — because it is the same method being called. Do you want the following?

System.out.println(S1.class.getSimpleName()); 

You cannot tell. It is the same method in the same class being invoked, even if you invoke it from a subclass. An IDE may suggest refactoring your code so all three instances refer to S instead of S1 or S2.

If you want to do anything like this, then consider

public static String method(Class c)

You may consider why you want to do this and if going non-static would be a help to make this easier.

Источник

Оцените статью