Java:如何从静态上下文中获取当前类的类对象?

标签 java reflection logging

我有一个将调用对象作为参数的日志记录函数。然后我对其调用 getClass().getSimpleName() 以便我可以轻松地获取类名以添加到我的日志条目中以便于引用。问题是,当我从静态方法调用我的日志函数时,我无法传入“this”。我的日志函数看起来像这样:

public static void log(Object o, String msg){
  do_log(o.getClass().getSimpleName()+" "+msg);
}
public void do_something(){
  log(this, "Some message");
}

但是假设我想从一个静态函数中登录:

public static void do_something_static(){
  log(this, "Some message from static");
}

显然 do_something_static() 不会工作,因为它是静态的并且“this”不在静态上下文中。我该如何解决这个问题?我可以在不使用反射的情况下做到这一点吗(因为我知道涉及很多开销并且它可能会影响性能,因为我记录了很多数据)

我知道我可能会以某种方式将当前类硬编码到调用中,但我确信当我将函数移动到另一个类时,我会忘记更新硬编码引用并且它将不再是正确。

谢谢!

最佳答案

您可以添加“Class”作为第一个参数并重载日志方法:

public class SomeClass {
    // Usage test:
    public static void main( String [] args ) {
        log( SomeClass.class, "Hola" );
        log( new java.util.Date(), "Hola" );
    }

    // Object version would call Class method... 
    public static void log( Object o , String msg ) {
        log( o.getClass(), msg );
    }
    public static void log( Class c ,  String message ) {
        System.out.println( c.getSimpleName() + " " + message );
    }
}

输出:

$ java SomeClass
SomeClass Hola
Date Hola

但是将调用类作为第一个参数传递感觉很糟糕。这就是面向对象模型发挥作用的地方,与“过程”风格相反。

您可以使用堆栈跟踪获取调用类,但正如您所提到的,如果调用它数千次就会产生开销。

但是如果您将 is 创建为类变量,那么如果碰巧有 1,000 个类使用此实用程序,那么类将只有一个实例,您将最多调用 1,000 次。

像这样会更好(这个 other 答案的细微变化):

public class LogUtility {

    private final String loggingFrom;

    public static LogUtility getLogger() {
        StackTraceElement [] s = new RuntimeException().getStackTrace();
        return new LogUtility( s[1].getClassName() );
    }

    private LogUtility( String loggingClassName ) {
        this.loggingFrom = "("+loggingClassName+") ";
    }

    public void log( String message ) {
        System.out.println( loggingFrom + message );
    }
}

使用测试:

class UsageClass {
    private static final LogUtility logger = LogUtility.getLogger();

    public static void main( String [] args ) {

        UsageClass usageClass = new UsageClass();

        usageClass.methodOne();
        usageClass.methodTwo();
        usageClass.methodThree();

    }
    private void methodOne() {
        logger.log("One");
    }
    private void methodTwo() {
        logger.log("Two");
    }
    private void methodThree() {
        logger.log("Three");
    }
}

输出

$ java UsageClass
(UsageClass) One
(UsageClass) Two
(UsageClass) Three

注意声明:

....
class UsageClass {
    // This is invoked only once. When the class is first loaded.
    private static final LogUtility logger = LogUtility.getLogger();
....

这样一来,无论您是从 objectA、objectB、objectC 还是类方法(如 main)中使用“记录器”,它们都将拥有一个记录器实例。

关于Java:如何从静态上下文中获取当前类的类对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1307477/

相关文章:

java - Android/Java - 通过反射获取隐藏类的类型

c# - 在 .Net 中使用私有(private)集初始化属性

java - 如果包含在 log.isDebugEnabled() 下,slf4j 记录器不会在 springboot 的控制台中打印日志

使用 BorderLayout 放置 Java 按钮

java - 调用 fillTable() 时出现 NullPointerException 错误

java - 以 "+0100"(例如)格式获取时区

java - 在 log4j 中为记录器设置不同级别的日志记录

java - 在运行时更改标题的颜色

c# - 如何从类型创建新的对象实例

logging - golang 1.8 : Embedded database for logging