2009-11-08 12 views
8

würde ich in dieser Angelegenheit etwas Hilfe,Wie erhält man den Namen der aufrufenden Klasse in Java?

Beispiel:

public class A { 

    private void foo() { 

      //Who Invoked me 

    } 

} 

public class B extends A { } 

public class C extends A { } 

public class D { 

    C.foo(); 

} 

Dies ist im Grunde das Szenario. Meine Frage ist, wie kann Methode foo() wissen, wer es anruft?

BEARBEITEN: Grundsätzlich versuche ich eine Datenbank-Ebene zu erstellen, und in Klasse A werde ich eine Methode erstellen, die SQL-Anweisungen generiert. Solche Anweisungen werden dynamisch generiert, indem die Werte aller öffentlichen Eigenschaften der aufrufenden Klasse abgerufen werden.

+1

Wird dieser Code sogar kompiliert? – Spoike

+0

Nein, es wird nicht kompiliert. –

+4

Eine Methode, die ihr Verhalten basierend auf der Klasse des Aufrufers ändert, macht die objektorientierte Programmierung wirklich auf dem Kopf. Wie kann man eine solche Klasse testen und sich im Test genauso verhalten wie in der Produktion? Es muss einen besseren Weg geben, um das zu implementieren, was Sie tun ... – daf

Antwort

26

Der einfachste Weg ist die folgende:

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

Aber im wirklichen sollte es keine Notwendigkeit dafür, es sei denn für einige Protokollierung, denn dies ist eine ziemlich teure Aufgabe. Was ist das Problem, für das Sie denken, dass dies die Lösung ist? Wir können uns viel bessere Vorschläge einfallen lassen.

bearbeiten: Sie wie folgt kommentiert:

grundsätzlich i'am eine Datenbank-Layer zu tun, und in der Klasse A versucht, werde ich eine Methode erstellen, die SQL-Anweisungen generieren, sind solche Aussagen dynamisch generiert durch Abrufen der Werte aller öffentlichen Eigenschaften der aufrufenden Klasse.

ich dann empfehlen für eine bestehende ORM library zu suchen, wie Hibernate, iBatis oder jede JPA implementation nach Ihrem Geschmack.

+0

im Grunde versuche ich, eine Datenbank-Ebene zu erstellen, und in Klasse A werde ich eine Methode erstellen, die SQL-Anweisungen generiert, wie solche Anweisungen dynamisch generiert werden Abrufen der Werte aller öffentlichen Eigenschaften der aufrufenden Klasse. –

+0

Füllen Ausnahmen die Stack-Trace im Konstruktor? Oder nur wenn geworfen? –

+6

@Mark: das ist wirklich schlechtes Design. Ich würde es tief durchdenken. –

4

foo() ist privat, so dass immer der Anrufer in der Klasse A.

+0

Klasse D hätte nicht kompiliert. – BalusC

14

Vielleicht für Ihren Anwendungsfall sein wird, wäre es sinnvoll, die Klasse des Anrufers zu übergeben in das Verfahren, wie:

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

Und es so etwas nennen:

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

+1 für + zeigt die * richtige * Möglichkeit, es zu tun. Lasst uns nicht mit Stack-Spuren für so etwas herumalbern. –

+2

Ja. Wenn der Aufrufer das grundlegende Design verfolgen muss, das Reflektion verwendet, um die Aufgabe auszuführen, lassen Sie die Verbindung klar sein.Übergeben Sie die Klasse oder eine Instanz. – CPerkins

+0

Im Allgemeinen würde ich Ihnen zustimmen, aber wenn Sie ein Framework der Art erstellen, kann es nützlich – mfeingold

-2

Vielleicht ist die Antwort hier:

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

Ich habe das versucht und es funktioniert gut. Dies liegt daran, dass jedes Java-Objekt Zugriff auf die Methode getClass() hat, die den Klassenaufrufer und den Methodennamen zurückgibt.

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

Verwendungsbeispiel:

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

Probe Logausgabe java.util.logging.Logger verwendet;

1. Februar 2017 23.14.50 rmg.data.model.DBTable (init) INFO:

0

A hacky Lösung ist sun.reflect.Reflection.getCallerClass getan.

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

Es ist Hacky, weil Sie, dass die Klasse, um sicherzustellen, haben die Reflection.getCallerClass()@CallerSensitive auf dem bootstrap ClassLoader für die Anmerkung geladen ruft zu arbeiten (die getCallerClass mit markiert). Daher ist es wahrscheinlich nicht die beste Lösung für ein Projekt, es sei denn, Ihr Projekt verwendet Java Agent, um Ihre Klassen zur Bootstrap-ClassLoader-Suche hinzuzufügen.

5

Java 9: ​​Stapel Gehen API

JEP 259 einen effizienten Standard-API für Stapel zu Fuß bietet, die leicht gefiltert und faul Zugang ermöglicht, die Informationen in Stack-Traces. Zunächst einmal sollten Sie eine Instanz von StackWalker erhalten:

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

StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE); 

Das Sie die getCallerClass() Methode aufrufen können:

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

Unabhängig davon, wie Sie konfiguriert die StackWalker Instanz, die getCallerClass Methode wird die Reflexionsrahmen ignorieren , verdeckte Bilder und solche sind verwandt mit MethodHandle s. Außerdem sollte diese Methode nicht im ersten Stack-Frame aufgerufen werden.

0

Wenn Sie slf4j als Anwendungsprotokollsystem verwenden. Sie können mit:

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

Ich denke, es ist schneller als neue Exception() getStackTrace(), da getStackTrace() alaways Klon Stacktrace zu tun..