Java - Тип класса изнутри статического блока инициализации - PullRequest
3 голосов
/ 31 мая 2010

Возможно ли получить тип класса внутри блока статической инициализации?

Это упрощенная версия того, что у меня сейчас есть:

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);
   }
}

Редактировать

Я выбрал принятый ответ, основываясь на том, что лучше всего применимо к моей проблеме, однако мне кажется, что все три текущих ответа имеют свои достоинства.

Ответы [ 3 ]

1 голос
/ 31 мая 2010

Чтобы получить класс во время выполнения, вы можете сделать что-то вроде

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 в качестве аргумента.

1 голос
/ 31 мая 2010

Нет, это невозможно без захвата трассировки стека (что намного хуже, чем ваш первоначальный подход и для которого я бы в любом случае предпочел Thread#getStackTrace() выше new Exception()).

Скорее выполняйте эту работу в нестатическом инициализаторе (или конструкторе по умолчанию) абстрактного класса, где вы проверяете статус initialized.

public abstract class SuperClass {

    {
        if (!isInitialized(getClass())) {
            initialize(getClass());
        }
    }

}

В свою очередь вызываемые методы могут безопасно static.

1 голос
/ 31 мая 2010

да, я часто использую это для инициализации статической переменной Log:

например. :

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