스택 추적 또는 리플렉션을 사용하여 메서드의 호출자를 어떻게 찾을 수 있습니까?


391

메소드의 호출자를 찾아야합니다. 스택 트레이스 또는 반사를 사용할 수 있습니까?


5
궁금한 점이 있지만 왜 이렇게해야합니까?
Juliet

2
알리미 이벤트가있는 Parent 클래스 (MVC 모델)가 있으며 내 하위 클래스의 setter만이 메소드를 호출합니다. 중복 인수로 코드를 작성하고 싶지 않습니다. 오히려 부모 클래스의 메소드가 그것을 호출 한 setter를 알아 내도록하고 싶습니다.
Sathish

30
@Sathish 당신이 그 디자인을 다시 생각해야 할 것 같은 소리
krosenvold

7
@Juliet 큰 코드 척을 리팩토링하는 과정에서 최근에 많은 것들에서 사용되는 메소드를 변경했습니다. 코드가 새로운 방법을 올바르게 사용하고 있는지 감지하는 특정 방법이 있으므로 해당 경우 호출 한 클래스와 줄 번호를 인쇄하고있었습니다. 로깅 외부에서는 이와 같은 실제 목적이 없습니다. API를 작성하고 싶지만 DontNameYourMethodFooException호출 메소드의 이름이 foo 인 경우 throw합니다 .
Cruncher

5
내 메소드의 호출자에게 귀중한 디버깅 도구를 얻을 수 있다는 것을 알게되었습니다. 내 메소드가 여러 곳에서 호출되는 경우 적절한 시간에 적절한 위치에서 호출됩니까? @Cruncher가 언급했듯이 디버깅이나 로깅 이외에는 유용성이 제한적일 수 있습니다.
오우거 시편 33

답변:


412
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()

Javadocs에 따르면 :

배열의 마지막 요소는 스택의 맨 아래를 나타내며 시퀀스에서 가장 최근의 메소드 호출입니다.

A는 StackTraceElementgetClassName(), getFileName(), getLineNumber()getMethodName().

원하는 인덱스를 결정하기 위해 실험해야 할 것입니다 (아마도 stackTraceElements[1]또는 [2]).


7
getStackTrace ()는 여전히 예외를 생성하므로 더 빠르지는 않습니다. 더 편리합니다.
Michael Myers

41
이 메소드는 호출자를 제공하지 않고 호출자의 유형 만 제공 합니다 . 메소드를 호출하는 객체에 대한 참조는 없습니다.
Joachim Sauer

3
참고 사항이지만 1.5 JVM Thread.currentThread (). getStackTrace ()는 새로운 Exception ()을 만드는 것보다 훨씬 느리게 보입니다 (약 3 배 느리게). 그러나 이미 언급했듯이 어쨌든 성능이 중요한 영역에서 이와 같은 코드를 사용해서는 안됩니다. ;) 1.6 JVM은 ~ 10 % 느려진 것 같습니다. Software Monkey가 말했듯이 "새로운 예외"방식보다 의도를 더 잘 표현합니다.
GaZ

21
@Eelco Thread.currentThread ()는 저렴합니다. Thread.getStackTrace ()는 Throwable.fillInStackTrace ()와 달리 검사하는 동일한 스레드에서 메소드가 호출된다는 보장이 없기 때문에 JVM이 "안전 점"을 작성하여 힙과 스택을 잠 가야합니다. 이 버그 리포트를 참조하십시오 bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
데이비드 두더지

7
@JoachimSauer 메소드를 호출하는 객체에 대한 참조를 얻는 방법을 알고 있습니까?
jophde

216

대체 솔루션은 이 개선 요청에 대한 주석에서 찾을 수 있습니다 . getClassContext()사용자 정의 방법을 사용하며 SecurityManager스택 추적 방법보다 빠릅니다.

다음 프로그램은 여러 가지 제안 된 방법의 속도를 테스트합니다 (가장 흥미로운 것은 내부 클래스에 있습니다) SecurityManagerMethod ).

/**
 * Test the speed of various methods for getting the caller class name
 */
public class TestGetCallerClassName {

  /**
   * Abstract class for testing different methods of getting the caller class name
   */
  private static abstract class GetCallerClassNameMethod {
      public abstract String getCallerClassName(int callStackDepth);
      public abstract String getMethodName();
  }

  /**
   * Uses the internal Reflection class
   */
  private static class ReflectionMethod extends GetCallerClassNameMethod {
      public String getCallerClassName(int callStackDepth) {
          return sun.reflect.Reflection.getCallerClass(callStackDepth).getName();
      }

      public String getMethodName() {
          return "Reflection";
      }
  }

  /**
   * Get a stack trace from the current thread
   */
  private static class ThreadStackTraceMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return Thread.currentThread().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Current Thread StackTrace";
      }
  }

  /**
   * Get a stack trace from a new Throwable
   */
  private static class ThrowableStackTraceMethod extends GetCallerClassNameMethod {

      public String getCallerClassName(int callStackDepth) {
          return new Throwable().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Throwable StackTrace";
      }
  }

  /**
   * Use the SecurityManager.getClassContext()
   */
  private static class SecurityManagerMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return mySecurityManager.getCallerClassName(callStackDepth);
      }

      public String getMethodName() {
          return "SecurityManager";
      }

      /** 
       * A custom security manager that exposes the getClassContext() information
       */
      static class MySecurityManager extends SecurityManager {
          public String getCallerClassName(int callStackDepth) {
              return getClassContext()[callStackDepth].getName();
          }
      }

      private final static MySecurityManager mySecurityManager =
          new MySecurityManager();
  }

  /**
   * Test all four methods
   */
  public static void main(String[] args) {
      testMethod(new ReflectionMethod());
      testMethod(new ThreadStackTraceMethod());
      testMethod(new ThrowableStackTraceMethod());
      testMethod(new SecurityManagerMethod());
  }

  private static void testMethod(GetCallerClassNameMethod method) {
      long startTime = System.nanoTime();
      String className = null;
      for (int i = 0; i < 1000000; i++) {
          className = method.getCallerClassName(2);
      }
      printElapsedTime(method.getMethodName(), startTime);
  }

  private static void printElapsedTime(String title, long startTime) {
      System.out.println(title + ": " + ((double)(System.nanoTime() - startTime))/1000000 + " ms.");
  }
}

Java 1.6.0_17을 실행하는 2.4GHz Intel Core 2 Duo MacBook의 출력 예 :

Reflection: 10.195 ms.
Current Thread StackTrace: 5886.964 ms.
Throwable StackTrace: 4700.073 ms.
SecurityManager: 1046.804 ms.

내부 반사 방법은 다른 방법 보다 훨씬 빠릅니다. 새로 작성된 스택 추적을 Throwable얻는 것이 현재 스택을 얻는 것보다 빠릅니다 Thread. 그리고 호출자 클래스를 찾는 비 내부적 방법 중 사용자 정의 SecurityManager가 가장 빠른 것 같습니다.

최신 정보

으로 lyomi는 에서 지적 이 댓글sun.reflect.Reflection.getCallerClass() 방법은 자바 7 업데이트 40에서 기본적으로 사용하지 않도록 설정하고 더 이것에 대해 자바 8. 읽기 완전히 제거 된 자바 버그 데이터베이스에서이 문제 .

업데이트 2

으로 zammbi이 발견했다, 오라클이되었다 변경의 철회하도록 강요 을 제거sun.reflect.Reflection.getCallerClass() . Java 8에서는 여전히 사용할 수 있지만 더 이상 사용되지 않습니다.

업데이트 3

3 년 후 : 현재 JVM으로 타이밍 업데이트.

> java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
> java TestGetCallerClassName
Reflection: 0.194s.
Current Thread StackTrace: 3.887s.
Throwable StackTrace: 3.173s.
SecurityManager: 0.565s.

5
예, 그런 것 같습니다. 그러나 예제에서 제공하는 타이밍은 백만 건의 호출에 대한 것이므로 사용 방법에 따라 문제가되지 않을 수 있습니다.
Johan Kaving 2016 년

1
프로젝트에서 반사를 제거하면 속도가 10 배 증가했습니다.
Kevin Parker

1
그렇습니다. 일반적으로 리플렉션은 느리지 만 (예 : stackoverflow.com/questions/435553/java-reflection-performance 참조 )이 특정 경우에는 내부 sun.reflect.Reflection 클래스를 사용하는 것이 가장 빠릅니다.
Johan Kaving 2016 년

1
실제로는 필요하지 않습니다. 반환 된 className을 인쇄하도록 위의 코드를 수정하여 확인할 수 있습니다 (루프 수를 1로 줄이는 것이 좋습니다). 모든 메소드가 동일한 className-TestGetCallerClassName을 리턴 함을 알 수 있습니다.
Johan Kaving

1
getCallerClass는 더 이상 사용되지 않으며 7u40에서 제거됩니다. sad :(
lyomi

36

this메서드에 참조를 전달하지 않으려는 것처럼 들립니다 . 전달 this은 현재 스택 추적을 통해 호출자를 찾는 것보다 낫습니다. 더 많은 OO 디자인으로 리팩토링하는 것이 더 좋습니다. 발신자를 알 필요는 없습니다. 필요한 경우 콜백 객체를 전달하십시오.


6
++ 발신자를 아는 것은 너무 많은 정보입니다. 필요한 경우 인터페이스를 전달할 수 있지만 주요 리팩토링이 필요할 가능성이 높습니다. @satish는 자신의 코드를 게시하고 재미있게 보내야합니다. :)
Bill K

15
이를 원하는 유효한 이유가 있습니다. 예를 들어 테스트하는 동안 도움이되는 경우가 몇 번있었습니다.
Eelco

2
@chillenious 알고 있습니다 :) LoggerFactory.getLogger(MyClass.class)클래스 리터럴을 전달하지 않아도되는 곳 과 같은 방법을 만들기 위해 직접했습니다 . 여전히 옳은 일이 거의 없습니다.
Craig P. Motlin

6
이것은 일반적으로 좋은 조언이지만 질문에 대답하지는 않습니다.
Navin

1
호출자에 대한 정보를 얻는 것이 올바른 설계 결정일 수있는 구체적인 예는 .NET INotifyPropertyChanged인터페이스를 구현할 때 입니다. 이 특정 예제는 Java가 아니지만 필드 / 게터를 리플렉션을위한 문자열로 모델링하려고 할 때 동일한 문제가 나타날 수 있습니다.
Chris Kerekes

30

Java 9-JEP 259 : 스택 워킹 API

JEP 259 는 스택 추적을위한 효율적인 표준 API를 제공하여 스택 추적의 정보를 쉽게 필터링하고 지연 액세스 할 수 있습니다. 스택 워킹 API 이전에는 스택 프레임에 액세스하는 일반적인 방법은 다음과 같습니다.

Throwable::getStackTraceThread::getStackTrace배열을 반환 StackTraceElement 각 스택 트레이스 요소의 클래스 이름과 메소드 이름을 포함하는 개체.

SecurityManager::getClassContext 보호 된 방법으로 SecurityManager서브 클래스가 클래스 컨텍스트에 액세스 입니다.

sun.reflect.Reflection::getCallerClass어쨌든 사용해서는 안되는 JDK 내부 메소드

이 API를 사용하면 일반적으로 비효율적입니다.

이러한 API를 사용하려면 VM에서 전체 스택의 스냅 샷을 열심히 캡처해야하며 전체 스택을 나타내는 정보를 반환합니다. 호출자가 스택의 최상위 몇 프레임에만 관심이있는 경우 모든 프레임을 검사하는 비용을 피할 수있는 방법이 없습니다.

즉시 발신자 클래스를 찾으려면 먼저 StackWalker:

StackWalker walker = StackWalker
                           .getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

그런 다음 getCallerClass():

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

또는 s와는 제 1 선행을 얻을 :walkStackFrameStackFrame

walker.walk(frames -> frames
      .map(StackWalker.StackFrame::getDeclaringClass)
      .skip(1)
      .findFirst());

15

원 라이너 :

Thread.currentThread().getStackTrace()[2].getMethodName()

2를 1로 바꿔야 할 수도 있습니다.


10

이 방법은 똑같은 작업을 수행하지만 더 간단하고 약간 더 성능이 좋으며 리플렉션을 사용하는 경우 해당 프레임을 자동으로 건너 뜁니다. 유일한 문제는 JRockit 1.4-> 1.6의 런타임 클래스에 포함되어 있지만 Sun 이외의 JVM에는 없을 수 있다는 것입니다. ( 공개 수업 이 아닙니다 ).

sun.reflect.Reflection

    /** Returns the class of the method <code>realFramesToSkip</code>
        frames up the stack (zero-based), ignoring frames associated
        with java.lang.reflect.Method.invoke() and its implementation.
        The first frame is that associated with this method, so
        <code>getCallerClass(0)</code> returns the Class object for
        sun.reflect.Reflection. Frames associated with
        java.lang.reflect.Method.invoke() and its implementation are
        completely ignored and do not count toward the number of "real"
        frames skipped. */
    public static native Class getCallerClass(int realFramesToSkip);

지금까지 무엇을 한 realFramesToSkip값이되어야한다, 태양 1.5 및 1.6 VM 버전 java.lang.System, getCallerClass () 호출라는 패키지 보호 방법이 sun.reflect.Reflection.getCallerClass(3)있지만, 헬퍼 클래스의 추가 프레임이 있기 때문에 내 도우미 유틸리티 클래스에 나는 4를 사용 기도.


16
JVM 구현 클래스를 사용하는 것은 정말 나쁜 생각입니다.
Lawrence Dol

7
유명한. 공개 클래스가 아니며 java.lang.System의 보호 된 메소드 getCallerClass ()가 IBM, JRockit 및 Sun을 포함하여 내가 본 모든 1.5 + VM에 존재하지만 귀하의 주장은 보수적으로 건전합니다. .
Nicholas

6
@Software Monkey는 평소와 같이 "모두 다릅니다". 디버깅 또는 테스트 로깅, 특히 프로덕션 코드로 끝나지 않는 경우 또는 배포 대상이 개발자의 PC 인 경우 이와 같은 작업을 수행하는 것이 좋습니다. 그런 경우에도 여전히 다르게 생각하는 사람은 : " 정말 나쁜 생각"을 추론하는 것보다 더 나은 추론 을 실제로 설명해야합니다 .

8
또한 유사한 논리로 JPA와 호환되지 않는 Hibernate 관련 기능을 사용할 때마다 항상 " 정말 나쁜 생각" 이라고 주장 할 수 있습니다 . 또는 다른 데이터베이스에서 사용할 수없는 Oracle 관련 기능을 사용하려는 경우 " 정말 나쁜 생각"입니다. 물론 그것은 특정 용도에 대한 안전 사고 방식과 확실히 좋은 충고지만, 자동으로, 어 ... 당신이있어하는 소프트웨어 구성하지 작동해서 버리고 유용한 도구 전혀 사용하지 ? 그것은 약간 융통성이없고 약간 어리 석습니다.

5
공급 업체별 클래스를 보호하지 않으면 문제가 발생할 가능성이 높아지지만 문제의 클래스가 존재하지 않는 경우 (또는 어떤 이유로 금지 된 경우) 정상적으로 저하 될 수있는 경로를 결정해야합니다. 벤더별 클래스 사용을 거부하는 정책은 제 생각에는 다소 순진합니다. 프로덕션 환경에서 사용하는 일부 라이브러리의 소스 코드를 살펴보고 그중 하나가 수행되는지 확인하십시오. (sun.misc.Unsafe 아마?)
Nicholas

7
     /**
       * Get the method name for a depth in call stack. <br />
       * Utility function
       * @param depth depth in the call stack (0 means current method, 1 means call method, ...)
       * @return method name
       */
      public static String getMethodName(final int depth)
      {
        final StackTraceElement[] ste = new Throwable().getStackTrace();

        //System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
        return ste[ste.length - depth].getMethodName();
      }

예를 들어, 디버그 목적으로 호출 메소드 행을 얻으려고 시도하면 해당 정적 메소드를 코딩하는 Utility 클래스를 통과해야합니다.
지나야 (이전의 Java1.4 코드, 잠재적 인 StackTraceElement 사용법을 보여주기 위해)

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
          * From the Stack Trace.
          * @return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
          */
        public static String getClassMethodLine()
        {
            return getClassMethodLine(null);
        }

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
          * Allows to get past a certain class.
          * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
          * @return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
          */
        public static String getClassMethodLine(final Class aclass)
        {
            final StackTraceElement st = getCallingStackTraceElement(aclass);
            final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
            +")] <" + Thread.currentThread().getName() + ">: ";
            return amsg;
        }

     /**
       * Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
       * Stored in array of the callstack. <br />
       * Allows to get past a certain class.
       * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
       * @return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
       * @throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
       */
      public static StackTraceElement getCallingStackTraceElement(final Class aclass)
      {
        final Throwable           t         = new Throwable();
        final StackTraceElement[] ste       = t.getStackTrace();
        int index = 1;
        final int limit = ste.length;
        StackTraceElement   st        = ste[index];
        String              className = st.getClassName();
        boolean aclassfound = false;
        if(aclass == null)
        {
            aclassfound = true;
        }
        StackTraceElement   resst = null;
        while(index < limit)
        {
            if(shouldExamine(className, aclass) == true)
            {
                if(resst == null)
                {
                    resst = st;
                }
                if(aclassfound == true)
                {
                    final StackTraceElement ast = onClassfound(aclass, className, st);
                    if(ast != null)
                    {
                        resst = ast;
                        break;
                    }
                }
                else
                {
                    if(aclass != null && aclass.getName().equals(className) == true)
                    {
                        aclassfound = true;
                    }
                }
            }
            index = index + 1;
            st        = ste[index];
            className = st.getClassName();
        }
        if(resst == null) 
        {
            //Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies 
            throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
        }
        return resst;
      }

      static private boolean shouldExamine(String className, Class aclass)
      {
          final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
            ) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
          return res;
      }

      static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
      {
          StackTraceElement   resst = null;
          if(aclass != null && aclass.getName().equals(className) == false)
          {
              resst = st;
          }
          if(aclass == null)
          {
              resst = st;
          }
          return resst;
      }

Java 1.4에서 작동하는 것이 필요 했으며이 답변이 매우 도움이되었습니다! 감사합니다!
RGO

6

나는 전에 이것을 한 적이있다. 새 예외를 만들고 스택 추적을 발생시키지 않고 스택 추적을 잡고 스택 추적을 검사 할 수 있습니다. 그러나 다른 대답에서 알 수 있듯이 비용이 많이 들기 때문에 빡빡한 루프에서는하지 마십시오.

성능이별로 중요하지 않은 앱에서 로깅 유틸리티를 사용하기 전에 수행했습니다 (실제로 버튼 클릭과 같은 동작에 결과를 표시하는 한 성능은 거의 중요하지 않습니다).

스택 추적을 얻을 수 있기 전에 예외는 단지 .printStackTrace () 였으므로 System.out을 내 자신의 생성 스트림으로 리디렉션 한 다음 (new Exception ()). printStackTrace (); System.out을 다시 리디렉션하고 스트림을 구문 분석하십시오. 재미있는 것들.


멋있는; 던질 필요가 없습니까?
krosenvold

아니, 적어도 그것은 내가 그것을 기억하는 방법입니다. 몇 년 동안 해보지 않았지만 예외를 새로 작성하면 객체가 생성되고 예외를 던지면 통과를 제외하고는 아무것도하지 않습니다. catch () 절에 추가하십시오.
Bill K

산뜻한. 나는 실제 예외를 시뮬레이션하기 위해 그것을 던지는 경향이있었습니다.
Sathish

Java 5부터 Thread에 현재 스택을 StackTraceElements의 배열로 가져 오는 메소드가 있습니다. 여전히 저렴하지는 않지만 이전의 예외 구문 분석 솔루션보다 저렴합니다.
Lawrence Dol

@Software Monkey 더 적절하다고 확신하지만 더 저렴하다고 말하는 이유는 무엇입니까? 나는 동일한 메커니즘이 사용될 것이라고 가정하고 그렇지 않은 경우 동일한 일을 할 때 왜 더 느리게 만드는가?
Bill K

1
private void parseExceptionContents(
      final Exception exception,
      final OutputStream out)
   {
      final StackTraceElement[] stackTrace = exception.getStackTrace();
      int index = 0;
      for (StackTraceElement element : stackTrace)
      {
         final String exceptionMsg =
              "Exception thrown from " + element.getMethodName()
            + " in class " + element.getClassName() + " [on line number "
            + element.getLineNumber() + " of file " + element.getFileName() + "]";
         try
         {
            out.write((headerLine + newLine).getBytes());
            out.write((headerTitlePortion + index++ + newLine).getBytes() );
            out.write((headerLine + newLine).getBytes());
            out.write((exceptionMsg + newLine + newLine).getBytes());
            out.write(
               ("Exception.toString: " + element.toString() + newLine).getBytes());
         }
         catch (IOException ioEx)
         {
            System.err.println(
                 "IOException encountered while trying to write "
               + "StackTraceElement data to provided OutputStream.\n"
               + ioEx.getMessage() );
         }
      }
   }

0

다음은이 주제에서 보여준 힌트를 바탕으로 작성한 코드의 일부입니다. 도움이 되길 바랍니다.

(이 코드를 개선하기 위해 어떤 제안도 자유롭게 해주세요. 알려주세요)

카운터:

public class InstanceCount{
    private static Map<Integer, CounterInstanceLog> instanceMap = new HashMap<Integer, CounterInstanceLog>();
private CounterInstanceLog counterInstanceLog;


    public void count() {
        counterInstanceLog= new counterInstanceLog();
    if(counterInstanceLog.getIdHashCode() != 0){
    try {
        if (instanceMap .containsKey(counterInstanceLog.getIdHashCode())) {
         counterInstanceLog= instanceMap .get(counterInstanceLog.getIdHashCode());
    }

    counterInstanceLog.incrementCounter();

            instanceMap .put(counterInstanceLog.getIdHashCode(), counterInstanceLog);
    }

    (...)
}

그리고 객체 :

public class CounterInstanceLog{
    private int idHashCode;
    private StackTraceElement[] arrayStackTraceElements;
    private int instanceCount;
    private String callerClassName;

    private StackTraceElement getProjectClasses(int depth) {
      if(depth< 10){
        getCallerClassName(sun.reflect.Reflection.getCallerClass(depth).getName());
        if(getCallerClassName().startsWith("com.yourproject.model")){
            setStackTraceElements(Thread.currentThread().getStackTrace());
            setIdHashCode();
        return arrayStackTraceElements[depth];
        }
        //+2 because one new item are added to the stackflow
        return getProjectClasses(profundidade+2);           
      }else{
        return null;
      }
    }

    private void setIdHashCode() {
        if(getNomeClasse() != null){
            this.idHashCode = (getCallerClassName()).hashCode();
        }
    }

    public void incrementaContador() {
    this.instanceCount++;
}

    //getters and setters

    (...)



}

0
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

class DBConnection {
    String createdBy = null;

    DBConnection(Throwable whoCreatedMe) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        whoCreatedMe.printStackTrace(pw);
        try {
            createdBy = os.toString();
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable(
                "Connection created from DBConnectionManager");
        DBConnection conn = new DBConnection(createdBy);
        System.out.println(conn.createdBy);
    }
}

또는

public static interface ICallback<T> { T doOperation(); }


public class TestCallerOfMethod {

    public static <T> T callTwo(final ICallback<T> c){
        // Pass the object created at callee to the caller
        // From the passed object we can get; what is the callee name like below.
        System.out.println(c.getClass().getEnclosingMethod().getName());
        return c.doOperation();
    }

    public static boolean callOne(){
        ICallback callBackInstance = new ICallback(Boolean){
            @Override
            public Boolean doOperation() 
            {
                return true;
            }
        };
        return callTwo(callBackInstance);
    }

    public static void main(String[] args) {
         callOne();
    }
}

0

이 방법을 사용하십시오 :

 StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
 stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
 System.out.println(e.getMethodName());

메소드 예제 코드의 호출자는 다음과 같습니다.

public class TestString {

    public static void main(String[] args) {
        TestString testString = new TestString();
        testString.doit1();
        testString.doit2();
        testString.doit3();
        testString.doit4();
    }

    public void doit() {
        StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
        System.out.println(e.getMethodName());
    }

    public void doit1() {
        doit();
    }

    public void doit2() {
        doit();
    }

    public void doit3() {
        doit();
    }

    public void doit4() {
        doit();
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.