2009-11-08 3 views
8

Я хотел бы получить некоторую помощь в этом вопросе,Как получить имя вызывающего класса в Java?

Пример:

public class A { 

    private void foo() { 

      //Who Invoked me 

    } 

} 

public class B extends A { } 

public class C extends A { } 

public class D { 

    C.foo(); 

} 

В основном это сценарий. Мой вопрос в том, как может метод foo() знать, кто его называет?

EDIT: В основном я пытаюсь выполнить слой базы данных, а в классе A создам метод, который будет генерировать SQL-выражения. Такие операторы динамически генерируются путем получения значений всех общедоступных свойств вызывающего класса.

+1

Будет ли этот код компилироваться? – Spoike

+0

Нет, он не будет компилироваться. –

+4

Метод, который изменяет его поведение на основе класса вызывающего, действительно превращает объектно-ориентированное программирование в его голову. Как вы можете протестировать такой класс и вести себя так же, как и в процессе тестирования? Там должен быть лучший способ реализовать то, что вы делаете ... – daf

ответ

26

Самый простой способ заключается в следующем:

String className = new Exception().getStackTrace()[1].getClassName(); 

Но в реале не должно быть никакой необходимости в этом нет, если для некоторых целей лесозаготовок, потому что это довольно дорогостоящая задача. Что это, проблема, для которой вы думаете, что это решение? Мы можем придумать -лучшие предложения.

Редактировать вы прокомментировали следующим образом:

в основном i'am пытается сделать базу данных слоя, и в классе А я создам метод, который будет генерировать SQL заявления, такие заявления динамически генерируется путем получения значений всех общедоступных свойств вызывающего класса.

Затем я настоятельно рекомендую искать существующую ORM library, такие как Hibernate, iBatis или любой JPA implementation на свой вкус.

+0

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

+0

За исключением того, что исключения заполняют трассировку стека в конструкторе? Или только когда бросили? –

+6

@Mark: это действительно плохой дизайн. Я бы *** глубоко *** пересмотрел его. –

4

Foo() является частным, так что абонент всегда будет в классе А.

+0

Класс D не был скомпилирован. – BalusC

14

Возможно, для вашего случая использования было бы целесообразно передать класс вызывающего абонента в метод, как:

public class A { public void foo(Class<?> c) { ... } } 

И называют это что-то вроде этого:

public class B { new A().foo(getClass() /* or: B.class */); } 
+2

+1 для + указателя * справа * способ сделать это. Давайте не будем испортить трассировки стека для чего-то вроде этого. –

+2

Да. Если вызывающий абонент должен выполнить основной проект, который использует отражение для выполнения задачи, пусть связь будет ясной.Передайте класс или экземпляр. – CPerkins

+0

В общем, я бы согласился с вами, но если вы создаете структуру такого рода, это может стать полезным. – mfeingold

-2

Ответ может быть здесь:

public class CallerMain { 
public void foo(){ 
    System.out.println("CallerMain - foo"); 
    System.out.println(this.getClass());//output- callerMain 
} 
public static void main(String[] args) { 
    A a = new A(); 
    CallerMain cm = new CallerMain(); 
    cm.foo(); 

} 

} 

class A{ 
public void foo(){ 
    System.out.println("A - foo"); 
    System.out.println(this.getClass());//output- A 
} 
} 
-1

Я пробовал это, и он хорошо работает. Это связано с тем, что каждый объект Java имеет доступ к методу getClass(), который возвращает вызывающего объекта класса и имя метода.

public Logger logger() { 
    return Logger.getLogger(getClass().toString()); 
} 

пример использования:

public DBTable(String tableName) { 
    this.tableName = tableName; 
    loadTableField(); 
    this.logger().info("done"); 
} 

журнал выходных данных с использованием java.util.logging.Logger;

1 февраля 2017 11:14:50 PM rmg.data.model.DBTable (INIT) INFO: сделано

0

Hacky решение sun.reflect.Reflection.getCallerClass.

public void foo() { 
    Class<?> caller = sun.reflect.Reflection.getCallerClass(); 
    // ... 
} 

Это Hacky, потому что вы должны убедиться, что класс, который вызывает Reflection.getCallerClass() загружен на bootstrap ClassLoader для аннотирования @CallerSensitive (который getCallerClass помечается) работать. Таким образом, это, вероятно, не лучшее решение для проекта, если только ваш проект не использует Java Agent, чтобы добавить ваши классы в поиск начальной загрузки ClassLoader.

5

Java 9: ​​Стек Walking API

JEP 259 обеспечивает эффективный стандартный API для стека ходьбе, что позволяет легко фильтровать и ленивым доступ, информацию в трассировки стека. Во-первых, вы должны получить экземпляр StackWalker:

import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; 
// other imports 

StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 

вы можете позвонить в getCallerClass() метод:

Class<?> callerClass = walker.getCallerClass(); 

Независимо от того, как вы настроили экземпляр StackWalker, метод getCallerClass будет игнорировать кадры отражения , скрытые кадры и те, которые связаны с MethodHandle s. Кроме того, этот метод не следует вызывать в первом стеке стека.

0

если вы используете slf4j как свою систему регистрации приложений. вы можете с помощью:

Class<?> source = org.slf4j.helpers.Util.getCallingClass(); 

Я думаю, что это быстрее, чем новый Exception() getStackTrace(), так как getStackTrace() alaways делают клон StackTrace..

Смежные вопросы