【问题标题】:Java - Class type from inside static initialization blockJava - 静态初始化块内部的类类型
【发布时间】:2026-02-17 06:45:03
【问题描述】:

是否可以从静态初始化块中获取类类型?

这是我目前拥有的简化版本::

class Person extends SuperClass {

   String firstName;

   static{
      // This function is on the "SuperClass":
      //  I'd for this function to be able to get "Person.class" without me
      //  having to explicitly type it in but "this.class" does not work in 
      //  a static context.
      doSomeReflectionStuff(Person.class);     // IN "SuperClass"
   }
}

这更接近我正在做的事情,即初始化一个数据结构,其中包含有关对象及其注释等的信息......也许我使用了错误的模式?

public abstract SuperClass{
   static void doSomeReflectionStuff( Class<?> classType, List<FieldData> fieldDataList ){
      Field[] fields = classType.getDeclaredFields();
      for( Field field : fields ){
         // Initialize fieldDataList
      }
   }
}

public abstract class Person {

   @SomeAnnotation
   String firstName;

   // Holds information on each of the fields, I used a Map<String, FieldData>
   //  in my actual implementation to map strings to the field information, but that
   //  seemed a little wordy for this example
   static List<FieldData> fieldDataList = new List<FieldData>();

   static{
      // Again, it seems dangerous to have to type in the "Person.class"
      //   (or Address.class, PhoneNumber.class, etc...) every time.
      //   Ideally, I'd liken to eliminate all this code from the Sub class
      //   since now I have to copy and paste it into each Sub class.
      doSomeReflectionStuff(Person.class, fieldDataList);
   }
}

编辑

我根据最适合我的问题的方法选择了公认的答案,但在我看来,当前所有三个答案都有其优点。

【问题讨论】:

    标签: java reflection static-initializer static-initialization


    【解决方案1】:

    不,不获取堆栈跟踪是不可能的(这比你最初的方法更糟糕,我无论如何都更喜欢Thread#getStackTrace()而不是new Exception())。

    宁可在检查initialized 状态的抽象类的非静态初始化程序(或默认构造函数)中完成这项工作。

    public abstract class SuperClass {
    
        {
            if (!isInitialized(getClass())) {
                initialize(getClass());
            }
        }
    
    }
    

    依次调用的方法可以安全地static

    【讨论】:

    • 感谢您的回答,这绝对比我拥有的要干净得多。对于每次创建对象实例时都会调用“isInitialized(getClass())”的效率论点,您会怎么说?
    • 至少比每次都反复初始化要便宜。如果将其存储为HashMap 密钥并使用fieldDataMap.containsKey(getClass()),则成本非常低。
    【解决方案2】:

    要在运行时获取类,您可以按照以下方式进行操作

    public class Test {
    public static void main(String[] args) {
        try{
            throw new Exception();
        }
        catch(Exception e){
            StackTraceElement[] sTrace = e.getStackTrace();
            // sTrace[0] will be always there
            String className = sTrace[0].getClassName();
            System.out.println(className);
    
        }
    }
    

    }

    不漂亮,但可以胜任(摘自http://www.artima.com/forums/flat.jsp?forum=1&thread=155230)。

    这意味着您仍然从子类进行调用(在堆栈跟踪中也是如此),但您不需要包含 XXX.class 作为参数。

    【讨论】:

      【解决方案3】:

      是的,我经常用它来初始化一个静态日志变量:

      例如:

      public class Project implements Serializable, Cloneable, Comparable<Project> {
          private static final Logger LOG = LoggerFactory.getLogger(Project.class);
          ...
      

      【讨论】: