如何从该类中的静态方法获取类的名称.例如
public class MyClass {
public static String getClassName() {
String name = ????; // what goes here so the string "MyClass" is returned
return name;
}
}
Run Code Online (Sandbox Code Playgroud)
为了把它放在上下文中,我实际上想要在异常中将类名作为消息的一部分返回.
too*_*kit 220
为了正确支持重构(重命名类),您应该使用以下任一方法:
MyClass.class.getName(); // full name with package
Run Code Online (Sandbox Code Playgroud)
或者(感谢@James Van Huis):
MyClass.class.getSimpleName(); // class name and no more
Run Code Online (Sandbox Code Playgroud)
Tom*_*ine 118
做什么工具包说.不要做这样的事情:
return new Object() { }.getClass().getEnclosingClass();
Run Code Online (Sandbox Code Playgroud)
Rei*_*ein 86
在Java 7+中,您可以在静态方法/字段中执行此操作:
MethodHandles.lookup().lookupClass()
Run Code Online (Sandbox Code Playgroud)
Art*_*pov 45
因此,我们有一种情况需要静态获取类对象或类完整/简单名称而不需要明确使用MyClass.class语法.
在某些情况下它可以非常方便,例如记录器实例
科特林 上层函数(在这种情况下,kotlin创建一个无法从kotlin代码访问的静态Java类).
我们有一些不同的变体来获取此信息:
new Object(){}.getClass().getEnclosingClass();
Tom Hawtin
指出- 强调
getClassContext()[0].getName();从SecurityManager
所指出克里斯托弗
new Throwable().getStackTrace()[0].getClassName();
通过计数路德维希
Thread.currentThread().getStackTrace()[1].getClassName();
来自Keksi
最后
MethodHandles.lookup().lookupClass();
来自Rein的精彩
我已为所有变体准备了jmh基准,结果如下:
# 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
Run Code Online (Sandbox Code Playgroud)
MethodHandles.lookup().lookupClass();
Run Code Online (Sandbox Code Playgroud)
new Object(){}.getClass().getEnclosingClass();
Run Code Online (Sandbox Code Playgroud)
如果你在很多地方需要它并且不希望你的字节码由于大量的匿名类而膨胀 - SecurityManager是你的朋友(第三个最佳选择).
但你不能只是打电话getClassContext()- 它在SecurityManager课堂上受到保护.你需要一些像这样的助手类:
// 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())
}
Run Code Online (Sandbox Code Playgroud)
getStackTrace()from例外的最后两个变体Thread.currentThread().非常低效,只能返回类名String,而不是Class<*>实例.如果你想为静态kotlin utils创建一个logger实例(比如我:),你可以使用这个帮助器:
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())
Run Code Online (Sandbox Code Playgroud)
用法示例:
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
}
Run Code Online (Sandbox Code Playgroud)
小智 38
这条指令工作正常:
Thread.currentThread().getStackTrace()[1].getClassName();
Run Code Online (Sandbox Code Playgroud)
小智 34
你可以像这样使用JNI做一些非常甜蜜的事情:
MyObject.java:
public class MyObject
{
static
{
System.loadLibrary( "classname" );
}
public static native String getClassName();
public static void main( String[] args )
{
System.out.println( getClassName() );
}
}
Run Code Online (Sandbox Code Playgroud)
然后:
javac MyObject.java
javah -jni MyObject
Run Code Online (Sandbox Code Playgroud)
然后:
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 );
}
Run Code Online (Sandbox Code Playgroud)
然后将C编译成一个名为的共享库libclassname.so并运行java!
*轻笑
小智 20
我使用它来初始化我的类(或注释)顶部的Log4j Logger.
PRO:Throwable已经加载,您可以通过不使用"IO heavy"SecurityManager来节省资源.
CON:关于这是否适用于所有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());
Run Code Online (Sandbox Code Playgroud)
Chr*_*fer 13
滥用SecurityManager
System.getSecurityManager().getClassContext()[0].getName();
Run Code Online (Sandbox Code Playgroud)
或者,如果没有设置,使用扩展它的内部类(下面的例子可以从Real的HowTo中羞耻地复制):
public static class CurrentClassGetter extends SecurityManager {
public String getClassName() {
return getClassContext()[1].getName();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您想要整个包名,请致电:
String name = MyClass.class.getCanonicalName();
Run Code Online (Sandbox Code Playgroud)
如果您只想要最后一个元素,请致电:
String name = MyClass.class.getSimpleName();
Run Code Online (Sandbox Code Playgroud)
逐字使用调用者的类MyClass.class.getName()实际上可以完成这项工作,但如果将此代码传播到需要此类名的许多类/子类,则很容易复制/粘贴错误.
而汤姆Hawtin的食谱其实不差,一个只需要做饭正确的方式:)
如果你有一个带有可以从子类调用的静态方法的基类,并且这个静态方法需要知道实际调用者的类,这可以像下面这样实现:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
174416 次 |
| 最近记录: |