zoukankan      html  css  js  c++  java
  • Java中获得当前静态类的类名

      通常在打印日志的时候需要输出类名,普通类可以用this.getClass(),但是静态类没有this,直接写类名耦合度高。

    参考了:

    https://stackoverflow.com/questions/936684/getting-the-class-name-from-a-static-method-in-java

    最有价值的回答:

    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
     * @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
    }

    总结

    Java7中的MethodHandles.lookup().lookupClass(),又快又简洁。

    如果条件不允许可以退而求其次用new Object(){}.getClass().getEnclosingClass()

    如果用Maven项目,默认是Source和Target都是1.5,需要加上,指定为1.7即可。

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • 相关阅读:
    快递物流查询接口介绍
    DWR
    html网页自动跳转页面代码
    提升Apache网站访问速度的优化方法
    synchronized实现原理
    window下的hosts
    [转]BX9054: 各浏览器对 document.execCommand 方法的首参数可选值范围存在差异
    浏览器关闭或刷新事件--window.onbeforeunload
    浏览器,tab页显示隐藏的事件监听--页面可见性
    http 304
  • 原文地址:https://www.cnblogs.com/ptqueen/p/8486628.html
Copyright © 2011-2022 走看看