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>
  • 相关阅读:
    (Problem 3)Largest prime factor
    (Problem 2)Even Fibonacci numbers
    (Problem 33)Digit canceling fractions
    (Problem 28)Number spiral diagonals
    多线程与多进程
    安装非英语版本的 Microsoft Visual Studio 2008 Service Pack 1 后,智能提示变为英文的临时补丁发布
    SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY的区别比较
    MSIL Instruction Table
    使用updatePanel报错 “不允许进行筛选”!
    SQLServer2008中恼人的"阻止保存要求重新创建表的更改"
  • 原文地址:https://www.cnblogs.com/ptqueen/p/8486628.html
Copyright © 2011-2022 走看看