Java的:如何从静态上下文获得当前类的类对象?(Java: How to get a class

2019-08-01 22:55发布

我有一个日志函数,它调用对象作为参数。 然后我就可以调用的getClass()。getSimpleName()这样我就可以轻松搞定类名添加到为便于参考我的日志条目。 问题是,当我把我的日志功能从一个静态方法,我不能在“此”通行证。 我的日志功能看起来是这样的:

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()不会工作,因为它是静态的,“这”不是一个静态的背景。 我怎样才能解决这个问题? 我能做到这一点,而无需使用反射(因为我的理解是有涉及大量的开销,因为我日志数据的。它可能会影响性能)

我知道,我也许可以硬编码当前类到呼叫莫名其妙,但我敢肯定,当我移动功能,另一个类,我会忘记更新硬编码的参考,这将不再是正确的。

谢谢!

Answer 1:

您可以添加“类”作为第一个参数和过载日志方法:

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

但感觉只是坏有作为第一个参数传递的调用类。 这里就是面向对象的模型进场时的“程序”的风格相反。

你可以得到使用堆栈跟踪调用的类,但你所提及般,如果你把它千百次会有一个开销。

但是 ,如果你创建是类变量的话,那就如果你碰巧有使用此实用程序类1000,你将不得不在1000调用只有一个类实例。

像这样的东西会更好(这微妙的变化等回答):

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();
....

这样,如果你使用“记录仪”,从对象A,对象B,objectC或从一个类的方法(如主)也没关系,他们都将有记录器的一个实例。



Answer 2:

查询堆栈跟踪也许worty您的问题。 你有3个可能的技术途径。

例外#的getStackTrace()

只需创建一个异常实例,并获得第一帧:

static String className() {
    return new RuntimeException().getStackTrace()[0].getClassName();
}

线

使用线程更容易:

static String className2() {
    return Thread.currentThread().getStackTrace()[1].getClassName();
}

这两种技术途径有,你不能重用他们的缺点。 所以,你可能要定义一个辅助类为:

class Helper {

    public static String getClassName() {
        return Thread.currentThread().getStackTrace()[2].getClassName();
    }
} 

现在你可以编程方式获取你的类名,没有硬编码的类名:

public static void log(Object o, String msg){
    do_log(Helper.getCClassName() + "  " + msg);
}


Answer 3:

改变方法log到:

public static void log(Class c, String msg){
  do_log(c.getSimpleName()+" "+msg);
}

如果do_something_static是类MyClassWithStatics然后do_something_static将成为:

public static void do_something_static(){
  log(MyClassWithStatics.class, "Some message from static");
}


Answer 4:

而不是“本”使用“MyClass.class”,让你的日志方法治疗类对象,而不的getClass()。

但是在做这个自己,考虑让日志框架做到这一点。



Answer 5:

你应该在类硬编码到在短期内呼叫。 如果你认为你会需要这个在各种项目中的地方,因为它是static ,你应该将其封装,并有它以班级为PARAM。

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


Answer 6:

好吧,如果你真的不想要硬编码像ClassName.class ,那么你可以尝试通过遍历堆栈跟踪来推断类。 幸运的是,有人已经做到了:)。 另外,可以考虑使用一个记录器,可以让你记录的东西不指定调用对象。



Answer 7:

会不会实施某种辛格尔顿你需要什么?

public class LogUtility {

    private final String loggingFrom;
    private static LogUtility instance;

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

    private LogUtility() {}

    private void setLoggingFrom(String loggingClassName){
        this.loggingFrom = loggingClassName;
    }

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

用法(随时随地在您的项目):

LogUtility.getLogger().log("Message");


Answer 8:

非静态的更换你的静态功能。 代替

Utils.do_something(...)

new Utils().do_something(...)


文章来源: Java: How to get a class object of the current class from a static context?