2009-11-08 38 views
8

Vorrei un po 'di aiuto su questa materia,Come ottenere il nome della classe chiamante in Java?

Esempio:

public class A { 

    private void foo() { 

      //Who Invoked me 

    } 

} 

public class B extends A { } 

public class C extends A { } 

public class D { 

    C.foo(); 

} 

Questo è fondamentalmente lo scenario. La mia domanda è: come può il metodo foo() sapere chi lo sta chiamando?

EDIT: Fondamentalmente sto cercando di creare un livello di database e in Classe A creerò un metodo che genererà istruzioni SQL. Tali istruzioni vengono generate dinamicamente ottenendo i valori di tutte le proprietà pubbliche della classe chiamante.

+1

Questo codice può essere compilato? – Spoike

+0

No, non verrà compilato. –

+4

Un metodo che modifica il suo comportamento in base alla classe del chiamante inverte davvero la programmazione orientata agli oggetti. Come puoi testare una classe del genere e comportarsi allo stesso modo nel test come nella produzione? Deve esserci un modo migliore per implementare quello che stai facendo ... – daf

risposta

26

modo più semplice è la seguente:

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

Ma in vero e proprio non ci dovrebbe essere bisogno di questo, a meno che per alcuni scopi di registrazione, perché questo è un compito abbastanza costoso. Di cosa si tratta, il problema per il quale pensi che questa sia la soluzione? Potremmo inventare suggerimenti molto migliori.

Edit: si ha commentato come segue:

fondamentalmente i'am cercando di fare un livello di database, e in classe A creerò un metodo che genera le istruzioni SQL, tali dichiarazioni sono dinamicamente generato ottenendo i valori di tutte le proprietà pubbliche della classe chiamante.

Ho quindi consiglio vivamente di cercare una ORM library esistente, ad esempio Hibernate, iBatis o qualsiasi JPA implementation al vostro gusto.

+0

in pratica sto provando a fare un database Layer, e in Classe A creerò un metodo che genererà istruzioni SQL, tali istruzioni sono generate dinamicamente da ottenere i valori di tutte le proprietà pubbliche della classe chiamante. –

+0

Le eccezioni riempiono la traccia dello stack nel costruttore? O solo quando lanciato? –

+6

@Mark: il design è davvero pessimo. Vorrei fottutamente ripensarci. –

4

foo() è privata, quindi il chiamante sarà sempre in classe A.

+0

La classe D non sarebbe stata compilata. – BalusC

14

Forse per il vostro caso d'uso avrebbe senso passare la classe del chiamante nel metodo, come:

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

e chiamare qualcosa di simile:

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

+1 per + indicando il * right * modo per farlo. Non roviniamo con le tracce dello stack per qualcosa di simile. –

+2

Sì. Se il chiamante deve perseguire il progetto di base che utilizza la riflessione per eseguire l'attività, lasciare che il collegamento sia chiaro.Passa la classe o un'istanza. – CPerkins

+0

In generale sarei d'accordo con te, ma se stai creando un framework di questo tipo può diventare utile – mfeingold

-2

può essere la risposta è qui:

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

Ho provato questo e funziona bene. È perché ogni oggetto Java ha accesso al metodo getClass() che restituisce il chiamante della classe e il nome del metodo.

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

esempio di utilizzo:

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

campione registro di output utilizzando java.util.logging.Logger;

1 Feb 2017 23:14:50 rmg.data.model.DBTable (init) INFORMAZIONI: fatto

0

Una soluzione hacky è sun.reflect.Reflection.getCallerClass.

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

E 'hacky perché si deve garantire che la classe che chiama Reflection.getCallerClass() viene caricata sul bootstrap ClassLoader per l'annotazione @CallerSensitive (che getCallerClass è codificata con) al lavoro. Pertanto, probabilmente non è la soluzione migliore per un progetto, a meno che il progetto non utilizzi lo Java Agent per aggiungere le classi alla ricerca ClassLoader di bootstrap.

5

Java 9: ​​Pila Walking API

JEP 259 fornisce un API standard efficiente per lo stack piedi che permette un facile filtraggio e l'accesso pigro per le informazioni in stack. Prima di tutto, si dovrebbe ottenere un'istanza di StackWalker:

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

StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 

La si può chiamare il metodo getCallerClass():

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

Indipendentemente da come è stato configurato l'istanza StackWalker, il metodo getCallerClass ignorerà i fotogrammi di riflessione , cornici nascoste e quelle relative a MethodHandle s. Inoltre, questo metodo non dovrebbe essere chiamato sul primo frame dello stack.

0

se si utilizza slf4j come sistema di registrazione dell'applicazione. è possibile utilizzare:

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

Penso che sia più veloce di new Exception() getStackTrace(), dal momento che alaways getStackTrace() facendo clone stacktrace..

Problemi correlati