2009-11-08 20 views
8

chciałbym jakąś pomoc w tej sprawie,Jak uzyskać nazwę klasy wywołującej w Javie?

Przykład:

public class A { 

    private void foo() { 

      //Who Invoked me 

    } 

} 

public class B extends A { } 

public class C extends A { } 

public class D { 

    C.foo(); 

} 

To jest w zasadzie taki scenariusz. Moje pytanie brzmi: jak metoda foo() może wiedzieć, kto ją nazywa?

EDYTOWANIE: Zasadniczo próbuję zrobić warstwę bazy danych, aw klasie A utworzę metodę, która wygeneruje instrukcje SQL. Takie instrukcje są generowane dynamicznie, pobierając wartości wszystkich publicznych właściwości klasy wywołującej.

+1

Czy ten kod będzie nawet kompilowany? – Spoike

+0

Nie, nie skompiluje się. –

+4

Metoda zmieniająca zachowanie w oparciu o klasę wywołującego naprawdę zmienia programowanie obiektowe na jego głowę. Jak możesz testować taką klasę i zachowywać ją tak samo w teście, jak w produkcji? Musi istnieć lepszy sposób implementacji tego, co robisz ... – daf

Odpowiedz

26

Najłatwiej jest następujący:

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

Ale w czasie rzeczywistym nie ma potrzeby do tego, chyba że dla pewnych celów rejestrowania, ponieważ jest to dość kosztowne zadanie. Co to jest, problem, dla którego uważasz, że to jest rozwiązanie? Możemy wymyślić - dużo - lepsze sugestie.

Edit: ty skomentował następująco:

zasadzie I'am próbuje zrobić warstwy bazy danych, aw klasie A i stworzy metodę, która będzie generować SQL, takie oświadczenia są dynamicznie generowane przez pobranie wartości wszystkich właściwości publicznych klasy wywołującej.

I wtedy bardzo polecam poszukać istniejącego ORM library, takich jak Hibernate, iBatis lub dowolny JPA implementation do gustu.

+0

zasadniczo próbuję zrobić warstwę bazy danych, aw klasie A utworzę metodę, która wygeneruje instrukcje SQL, takie instrukcje są generowane dynamicznie przez uzyskiwanie wartości wszystkich właściwości publicznych klasy wywołującej. –

+0

Czy wyjątki wypełniają ślad stosu w konstruktorze? Lub tylko po rzuceniu? –

+6

@ Mark: to naprawdę zły projekt. Chciałbym *** głęboko przemyśl to ponownie. –

4

Foo() jest prywatny, więc rozmówca zawsze będzie w klasie A.

+0

Klasa D nie skompilowałaby się. – BalusC

14

Być może w Twoim przypadku użycia byłoby sensu przechodzić klasę rozmówcy do metody, jak:

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

i nazywają to coś takiego:

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

+1 za + wskazanie * właściwego * sposobu zrobienia tego. Nie zepsujmy śladów stosów na coś takiego. –

+2

Tak. Jeśli osoba dzwoniąca musi realizować podstawowy projekt, który wykorzystuje odbicie do wykonania zadania, niech połączenie będzie jasne.Przekaż klasę lub instancję. – CPerkins

+0

Ogólnie rzecz biorąc, zgadzam się z tobą, ale jeśli tworzysz strukturę tego rodzaju, może stać się użyteczny – mfeingold

-2

Może być odpowiedź tutaj:

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

Próbowałem tego i działa dobrze. Dzieje się tak, ponieważ każdy obiekt Java ma dostęp do metody getClass(), która zwraca klasę wywołującą i nazwę metody.

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

przykład użycie:

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

próbki log wyjściowy to java.util.logging.Logger;

01 lutego 2017 23:14:50 rmg.data.model.DBTable (startowych) INFO: zrobić

0

hacky rozwiązaniem jest sun.reflect.Reflection.getCallerClass.

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

Jest hacky bo trzeba upewnić się, że klasa, która wywołuje Reflection.getCallerClass() jest ładowany na bootstrap ClassLoader dla adnotacji @CallerSensitivegetCallerClass (który jest oznaczony) do pracy. W związku z tym, prawdopodobnie nie jest to najlepsze rozwiązanie dla projektu, chyba że Twój projekt używa numeru Java Agent, aby dodać swoje klasy do przeszukiwania klasy ładującej klasy.

5

Java 9: ​​Stos Walking API

JEP 259 zapewnia wydajne standardowe API dla stosu pieszego, który umożliwia łatwe filtrowanie i leniwy, dostęp do informacji w ślady stosu. Po pierwsze, należy uzyskać instancję StackWalker:

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

StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 

puszki wywołać metodę getCallerClass():

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

Niezależnie od sposobu skonfigurowania instancji StackWalker metoda getCallerClass zignoruje ramek odbicie , ukryte ramki i te są powiązane z MethodHandle s. Ponadto tej metody nie należy wywoływać na ramce pierwszego stosu.

0

jeśli używasz slf4j jako swojego systemu rejestrowania aplikacji. można za pomocą:

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

myślę, że to szybciej niż nowy wyjątek() getStackTrace(), ponieważ getStackTrace() alaways robi klon StackTrace..

Powiązane problemy