2009-11-08 5 views
8

Je voudrais de l'aide à ce sujet,Comment obtenir le nom de la classe appelante en Java?

Exemple:

public class A { 

    private void foo() { 

      //Who Invoked me 

    } 

} 

public class B extends A { } 

public class C extends A { } 

public class D { 

    C.foo(); 

} 

Ceci est essentiellement le scénario. Ma question est de savoir comment la méthode foo() peut savoir qui l'appelle? Fondamentalement, j'essaye de faire un calque de base de données, et dans la classe A je vais créer une méthode qui va générer des instructions SQL. Ces instructions sont générées dynamiquement en obtenant les valeurs de toutes les propriétés publiques de la classe appelante.

+1

Ce code compilera-t-il même? – Spoike

+0

Non, il ne sera pas compilé. –

+4

Une méthode qui modifie son comportement en fonction de la classe de l'appelant active vraiment la programmation orientée objet sur sa tête. Comment pouvez-vous tester une telle classe et se comporter de la même manière dans le test que dans la production? Il doit y avoir une meilleure façon d'implémenter ce que vous faites ... – daf

Répondre

26

plus simple est les suivantes:

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

Mais dans la réalité il devrait y avoir pas besoin de cela, à moins que certaines fins de l'exploitation forestière, parce que cela est une tâche assez cher. Qu'est-ce que c'est, le problème pour lequel vous pensez que c'est la solution? Nous pouvons proposer de très bonnes suggestions.

Modifier vous a commenté comme suit:

essentiellement i'am essayer de faire une base de données couche, et dans la classe A i va créer une méthode qui va générer des instructions SQL, ces déclarations sont dynamiquement généré en obtenant les valeurs de toutes les propriétés publiques de la classe appelante.

Je puis vous recommandons fortement de chercher une ORM library existante, comme Hibernate, iBatis ou tout JPA implementation à votre goût.

+0

fondamentalement j'essaye de faire un calque de base de données, et dans la classe A je créerai une méthode qui génèrera des déclarations sql, de telles déclarations sont générées dynamiquement par obtenir les valeurs de toutes les propriétés publiques de la classe appelante. –

+0

Est-ce que les exceptions remplissent la trace de la pile dans le constructeur? Ou seulement quand jeté? –

+6

@Mark: c'est vraiment un mauvais design. Je *** *** profondément *** le reconsidérer. –

4

foo() est privé, de sorte que l'appelant sera toujours en classe A.

+0

La classe D n'aurait pas été compilée. – BalusC

14

Peut-être pour votre cas d'utilisation, il serait logique de passer la classe de l'appelant dans la méthode, comme:

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

et l'appeler quelque chose comme ceci:

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

+1 pour + indiquant la bonne façon de le faire. Ne gâchons pas avec des traces de pile pour quelque chose comme ça. –

+2

Oui. Si l'appelant doit poursuivre la conception de base qui utilise la réflexion pour effectuer la tâche, laissez le lien être clair.Passez la classe ou une instance. – CPerkins

+0

En général, je serais d'accord avec vous, mais si vous créez un cadre des sortes il peut devenir utile – mfeingold

-2

Peut être la réponse est ici:

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

J'ai essayé ceci et cela fonctionne bien. C'est parce que chaque objet Java a accès à la méthode getClass() qui renvoie l'appelant de la classe et le nom de la méthode.

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

Exemple d'utilisation:

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

journal de sortie d'échantillon à l'aide java.util.logging.Logger;

1 février 2017 23:14:50 rmg.data.model.DBTable (init) INFO: fait

0

Une solution aki est sun.reflect.Reflection.getCallerClass.

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

Il est hacky parce que vous devez vous assurer que la classe qui appelle Reflection.getCallerClass() est chargé sur le bootstrap ClassLoader pour l'annotation @CallerSensitive (qui est getCallerClass taggés avec) au travail. En tant que tel, ce n'est probablement pas la meilleure solution pour un projet à moins que votre projet n'utilise un Java Agent pour ajouter vos classes à la recherche BootLoad ClassLoader.

5

Java 9: ​​Stack Walking API

JEP 259 fournit une API standard efficace pour la marche de la pile qui permet de filtrer facilement, et l'accès paresseux pour, les informations contenues dans les traces de pile. Tout d'abord, vous devez obtenir une instance de StackWalker:

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

StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 

Le vous pouvez appeler la méthode getCallerClass():

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

Quelle que soit la façon dont vous avez configuré l'instance StackWalker, la méthode getCallerClass ignore les cadres de réflexion , les cadres cachés et ceux qui sont liés à MethodHandle s. En outre, cette méthode ne doit pas être appelée sur le premier cadre de pile. Si vous utilisez slf4j comme système de consignation d'application,

0

vous pouvez en utilisant:

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

Je pense qu'il est, depuis getStackTrace() alaways faisant stacktrace clone plus vite que les nouvelles exceptions() getStackTrace()..

Questions connexes