因此,我们有一种情况需要静态获取类对象或类完整/简单名称而不需要明确使用MyClass.class语法。
在某些情况下它可以非常方便,例如kotlin上层函数的logger实例(在这种情况下,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
结论
最好的变种,相当干净,怪异的快速。
仅在Java 7和Android API 26之后可用!
MethodHandles.lookup().lookupClass();
如果您需要Android或Java 6的此功能,您可以使用第二个最佳变体。它也相当快,但在每个使用地点创建一个匿名类 :(
new Object(){}.getClass().getEnclosingClass();
如果你在很多地方需要它并且不希望你的字节码由于大量的匿名类而膨胀 - 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())
}
您可能根本不需要使用基于getStackTrace()from例外的最后两个变体Thread.currentThread()。非常低效,只能返回类名String,而不是Class实例。
PS
如果你想为静态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())
用法示例:
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
}