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>
  • 相关阅读:
    win7承载网络状态不可用,无线网卡驱动更新后也仍然不可用。
    oracle中读写blob字段的问题
    The import javax.servlet cannot be resolved
    关于BLOB数据类型插入ORACLE数据库的操作
    Android Spinner自动弹出列表,设置title
    java.lang.LinkageError: loader constraint violation: when resolving interface... 异常解决
    Java获取网络时间
    android 改变CheckBox和后面文字的间距
    大白话系列之C#委托与事件讲解(序言)
    大白话系列之C#委托与事件讲解(一)
  • 原文地址:https://www.cnblogs.com/ptqueen/p/8486628.html
Copyright © 2011-2022 走看看