Làm cách nào để tìm người gọi phương thức bằng stacktrace hoặc Reflection?


392

Tôi cần tìm người gọi của một phương thức. Có thể sử dụng stacktrace hoặc phản chiếu?


5
Chỉ tự hỏi, nhưng tại sao bạn cần phải làm điều này?
Juliet

2
Tôi có một lớp Parent (mô hình MVC) với một sự kiện thông báo và chỉ setters của các lớp con của tôi gọi phương thức này. tôi không muốn xả rác mã của tôi với một đối số dư thừa. Tôi muốn để phương thức trong lớp cha tìm ra setter gọi nó.
Sathish

30
@Sathish Nghe có vẻ như bạn nên nghĩ lại thiết kế đó
krosenvold

7
@Juliet Là một phần của việc tái cấu trúc một mớ mã lớn, gần đây tôi đã thay đổi một phương thức được sử dụng bởi nhiều thứ. Có một cách nhất định để phát hiện xem mã có sử dụng đúng phương thức mới hay không, vì vậy tôi đã in lớp và số dòng gọi nó trong các trường hợp đó. Ngoài đăng nhập, tôi thấy không có mục đích thực sự cho một cái gì đó như thế này. Mặc dù tôi muốn viết API ngay bây giờ, DontNameYourMethodFooExceptionnếu phương thức gọi được đặt tên là foo.
Cruncher

5
Tôi thấy việc có thể gọi cho người gọi phương thức của mình một công cụ gỡ lỗi vô giá: đó là cách tìm kiếm trên web đưa tôi đến đây. Nếu phương thức của tôi đang được gọi từ nhiều nơi, liệu nó có được gọi từ đúng địa điểm vào đúng thời điểm không? Ngoài việc gỡ lỗi hoặc ghi nhật ký, tính hữu dụng có lẽ bị hạn chế tối đa, như @Cruncher đề cập.
Ogre Psalm33

Câu trả lời:


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

Theo Javadocs:

Phần tử cuối cùng của mảng biểu thị phần dưới cùng của ngăn xếp, đây là cách gọi phương thức gần đây nhất trong chuỗi.

Một StackTraceElementgetClassName(), getFileName(), getLineNumber()getMethodName() .

Bạn sẽ phải thử nghiệm để xác định chỉ mục nào bạn muốn (có thể stackTraceElements[1]hoặc [2]).


7
Tôi nên lưu ý rằng getStackTrace () vẫn tạo Ngoại lệ, vì vậy điều này không thực sự nhanh hơn - chỉ cần thuận tiện hơn.
Michael Myers

42
Lưu ý rằng phương pháp này sẽ không cung cấp cho bạn người gọi mà chỉ cung cấp loại người gọi . Bạn sẽ không có một tham chiếu đến đối tượng gọi phương thức của bạn.
Joachim Sauer

3
Chỉ là một ghi chú bên lề, nhưng trên 1.5 JVM Thread.cienThread (). GetStackTrace () dường như chậm hơn rất nhiều so với việc tạo Exception () mới (chậm hơn khoảng 3 lần). Nhưng như đã lưu ý, dù sao bạn cũng không nên sử dụng mã như thế này trong một lĩnh vực quan trọng về hiệu năng. ;) Một JVM 1.6 dường như chỉ chậm hơn ~ 10% và, như Software Monkey đã nói, nó thể hiện ý định tốt hơn so với cách "Ngoại lệ mới".
GaZ

21
@Eelco Thread.cienThread () là giá rẻ. Thread.getStackTrace () rất tốn kém bởi vì, không giống như throwable.fillInStackTrace (), không có gì đảm bảo phương thức được gọi bởi cùng một luồng mà nó đang kiểm tra, do đó JVM phải tạo ra một "điểm an toàn" - khóa heap và stack. Xem báo cáo lỗi này: bug.sun.com/bugdatabase/view_orms.do?orms_id=6375302
David Moles

7
@JoachimSauer bạn có biết một cách để có được một tham chiếu đến đối tượng gọi phương thức này không?
jophde

216

Một giải pháp thay thế có thể được tìm thấy trong một bình luận cho yêu cầu này để tăng cường . Nó sử dụng getClassContext()phương thức của một tùy chỉnhSecurityManager và dường như nhanh hơn phương thức theo dõi ngăn xếp.

Chương trình sau đây kiểm tra tốc độ của các phương thức được đề xuất khác nhau (bit thú vị nhất là ở lớp bên trong 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.");
  }
}

Một ví dụ về đầu ra từ MacBook Intel Core 2 Duo 2,4 GHz của tôi chạy Java 1.6.0_17:

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

Phương pháp Reflection nội bộ là nhiều nhanh hơn so với những người khác. Nhận một dấu vết ngăn xếp từ một mới được tạo ra Throwablenhanh hơn so với nhận được từ hiện tại Thread. Và trong số các cách tìm nội bộ của lớp người gọi, tùy chỉnhSecurityManager dường như là nhanh nhất.

Cập nhật

Như lyomi chỉ ra trong nhận xét này , sun.reflect.Reflection.getCallerClass()phương thức đã bị tắt theo mặc định trong bản cập nhật Java 7 40 và bị xóa hoàn toàn trong Java 8. Đọc thêm về vấn đề này trong cơ sở dữ liệu lỗi Java .

Cập nhật 2

Như zammbi đã tìm thấy, Oracle đã buộc phải rút lui khỏi sự thay đổi đã loại bỏ sun.reflect.Reflection.getCallerClass(). Nó vẫn có sẵn trong Java 8 (nhưng nó không được dùng nữa).

Cập nhật 3

3 năm sau: Cập nhật về thời gian với JVM hiện tại.

> 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
Vâng, có vẻ như vậy. Nhưng lưu ý rằng thời gian tôi đưa ra trong ví dụ là cho một triệu cuộc gọi - vì vậy tùy thuộc vào cách bạn đang sử dụng, đây có thể không phải là vấn đề.
Johan Kaving

1
Đối với tôi loại bỏ sự phản chiếu từ dự án của tôi dẫn đến tăng tốc độ gấp 10 lần.
Kevin Parker

1
Có, sự phản chiếu nói chung là chậm (xem ví dụ stackoverflow.com/questions/435553/java-reflection-performance ), nhưng trong trường hợp cụ thể này, sử dụng lớp sun.reflect.Reflection bên trong là nhanh nhất.
Johan Kaving

1
Nó thực sự không cần thiết. Bạn có thể xác minh nó bằng cách sửa đổi mã ở trên để in className được trả về (và tôi khuyên bạn nên giảm số vòng lặp xuống 1). Bạn sẽ thấy rằng tất cả các phương thức trả về cùng một className - TestGetCallerClassName.
Johan Kave

1
getCallerClass không được dùng nữa và sẽ bị xóa trong 7u40 .. buồn :(
lyomi

36

Âm thanh như bạn đang cố gắng tránh chuyển một tham chiếu đến thisphương thức. Vượt qua thislà cách tốt hơn so với việc tìm kiếm người gọi thông qua theo dõi ngăn xếp hiện tại. Tái cấu trúc cho một thiết kế OO nhiều hơn thậm chí còn tốt hơn. Bạn không cần phải biết người gọi. Vượt qua một đối tượng gọi lại nếu cần thiết.


6
++ Biết người gọi là quá nhiều thông tin. Nếu bạn phải, bạn có thể vượt qua trong một giao diện, nhưng rất có thể cần phải tái cấu trúc chính. @satish nên đăng mã của anh ấy và để chúng tôi vui vẻ với nó :)
Bill K

15
Lý do hợp lệ cho việc muốn làm điều này tồn tại. Tôi đã có một vài lần tôi thấy nó hữu ích trong quá trình thử nghiệm chẳng hạn.
Eelco

2
@chillenious Tôi biết :) Tôi đã tự mình thực hiện để tạo ra một phương pháp như LoggerFactory.getLogger(MyClass.class)nơi tôi không phải vượt qua trong lớp. Đó vẫn hiếm khi là điều đúng đắn để làm.
Craig P. Motlin

6
Đây là lời khuyên tốt nói chung, nhưng nó không trả lời câu hỏi.
Navin

1
Một ví dụ cụ thể về thời điểm có thể là quyết định thiết kế ĐÚNG để có được thông tin về người gọi là khi thực hiện INotifyPropertyChangedgiao diện .NET . Mặc dù ví dụ cụ thể này không có trong Java, nhưng vấn đề tương tự có thể tự biểu hiện khi cố gắng mô hình hóa các trường / getters dưới dạng chuỗi cho Reflection.
Chris Kerekes

31

Java 9 - JEP 259: API đi bộ xếp chồng

JEP 259 cung cấp API tiêu chuẩn hiệu quả để đi bộ ngăn xếp cho phép dễ dàng lọc và truy cập lười biếng vào thông tin trong dấu vết ngăn xếp. Trước API Stack-Walking, các cách phổ biến để truy cập các khung stack là:

Throwable::getStackTraceThread::getStackTracetrả về một mảng các StackTraceElementđối tượng, chứa tên lớp và tên phương thức của từng phần tử theo dõi ngăn xếp.

SecurityManager::getClassContext là một phương pháp được bảo vệ, cho phép một SecurityManager lớp con truy cập vào bối cảnh của lớp.

sun.reflect.Reflection::getCallerClassPhương thức nội bộ JDK mà bạn không nên sử dụng

Sử dụng các API này thường không hiệu quả:

Các API này yêu cầu VM háo hức chụp một ảnh chụp nhanh của toàn bộ ngăn xếp và chúng trả về thông tin đại diện cho toàn bộ ngăn xếp. Không có cách nào để tránh chi phí kiểm tra tất cả các khung nếu người gọi chỉ quan tâm đến một vài khung trên cùng trên ngăn xếp.

Để tìm lớp người gọi ngay lập tức, trước tiên hãy lấy StackWalker:

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

Sau đó, hoặc gọi getCallerClass():

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

hoặc walkcác StackFrames và nhận được trước đầu tiên StackFrame:

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

15

Oneliner :

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

Lưu ý rằng bạn có thể cần thay 2 bằng 1.


10

Phương pháp này thực hiện tương tự nhưng đơn giản hơn và có thể hiệu quả hơn một chút và trong trường hợp bạn đang sử dụng sự phản chiếu, nó sẽ tự động bỏ qua các khung đó. Vấn đề duy nhất là nó có thể không có trong các JVM không thuộc Mặt trời, mặc dù nó được bao gồm trong các lớp thời gian chạy của JRockit 1.4 -> 1.6. (Điểm là, nó không phải là một lớp học công cộng ).

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);

Theo như realFramesToSkipgiá trị của phiên bản Sun 1.5 và 1.6 VM java.lang.System, có một phương thức được bảo vệ gói gọi là getCallerClass () gọi sun.reflect.Reflection.getCallerClass(3), nhưng trong lớp tiện ích trợ giúp của tôi, tôi đã sử dụng 4 vì có thêm khung của lớp trình trợ giúp cầu khẩn.


16
Sử dụng các lớp triển khai JVM là một ý tưởng thực sự tồi tệ.
Lawrence Dol

7
Lưu ý Tôi đã xác định rằng nó không phải là một lớp công khai và phương thức được bảo vệ getCallerClass () trong java.lang.System có mặt trên tất cả hơn 1,5 VM mà tôi đã xem, bao gồm cả IBM, JRockit và Sun, nhưng khẳng định của bạn là âm thanh bảo thủ .
Nicholas

6
@Software Monkey, cũng như thường lệ, "tất cả phụ thuộc". Làm một cái gì đó như thế này để hỗ trợ gỡ lỗi hoặc kiểm tra ghi nhật ký - đặc biệt là nếu nó không bao giờ kết thúc trong mã sản xuất - hoặc nếu mục tiêu triển khai hoàn toàn là PC của nhà phát triển, có lẽ sẽ ổn. Bất cứ ai vẫn nghĩ khác ngay cả trong những trường hợp như vậy: bạn thực sự cần phải giải thích lý do "ý tưởng thực sự xấu" tốt hơn là chỉ nói xấu ...

8
Ngoài ra, bằng logic tương tự, bạn cũng có thể lập luận rằng bất cứ khi nào bạn sử dụng tính năng dành riêng cho Hibernate không tương thích với JPA, đó luôn là một " ý tưởng thực sự tồi". Hoặc nếu bạn sẽ sử dụng các tính năng dành riêng cho Oracle không có trong các cơ sở dữ liệu khác, thì đó là một " ý tưởng thực sự tồi tệ". Chắc chắn đó là một suy nghĩ an toàn hơn và chắc chắn là lời khuyên tốt cho một số mục đích sử dụng nhất định, nhưng tự động loại bỏ các công cụ hữu ích chỉ vì nó không hoạt động với cấu hình phần mềm mà bạn, bạn không sử dụng ? Đó là một chút quá không linh hoạt và một chút ngớ ngẩn.

5
Việc sử dụng các lớp cụ thể của nhà cung cấp không được bảo vệ sẽ có khả năng xảy ra sự cố cao hơn, nhưng người ta nên xác định đường dẫn đến sự xuống cấp một cách duyên dáng nếu không có lớp nào trong câu hỏi (hoặc bị cấm vì một số lý do). Theo tôi, một chính sách từ chối sử dụng bất kỳ lớp cụ thể nào của nhà cung cấp là một chút ngây thơ. Chọc vào mã nguồn của một số thư viện bạn sử dụng trong sản xuất và xem có ai trong số họ làm điều này không. (sun.misc.Unsafe có lẽ?)
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();
      }

Ví dụ: nếu bạn cố lấy dòng phương thức gọi cho mục đích gỡ lỗi, bạn cần vượt qua lớp Utility trong đó bạn mã hóa các phương thức tĩnh đó:
(mã java1.4 cũ, chỉ để minh họa cách sử dụng StackTraceEuity tiềm năng)

        /**
          * 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;
      }

Tôi cần một cái gì đó hoạt động với Java 1.4 và câu trả lời này rất hữu ích! Cảm ơn bạn!
RGO

6

Tôi đã làm điều này trước đây. Bạn chỉ có thể tạo một ngoại lệ mới và lấy dấu vết ngăn xếp trên đó mà không ném nó, sau đó kiểm tra dấu vết ngăn xếp. Như câu trả lời khác nói, nó cực kỳ tốn kém - đừng làm điều đó trong một vòng lặp chặt chẽ.

Tôi đã từng làm điều đó trước đây cho một tiện ích ghi nhật ký trên một ứng dụng mà hiệu suất không quan trọng lắm (Hiệu suất hiếm khi thực sự quan trọng, thực tế - miễn là bạn hiển thị kết quả cho một hành động như bấm nút nhanh chóng).

Đó là trước khi bạn có thể có được dấu vết ngăn xếp, ngoại lệ chỉ có .printStackTrace () vì vậy tôi phải chuyển hướng System.out sang luồng sáng tạo của riêng tôi, sau đó (Ngoại lệ mới ()). PrintStackTrace (); Chuyển hướng System.out trở lại và phân tích luồng. Công cụ thú vị.


Mát mẻ; bạn không phải ném nó?
krosenvold

Không, ít nhất đó là cách tôi nhớ nó, tôi đã không làm điều đó trong một vài năm, nhưng tôi khá chắc chắn rằng việc tạo ra một ngoại lệ chỉ là tạo ra một vật thể, và ném ngoại lệ đó không làm gì cả ngoại trừ nó với mệnh đề Catch ().
Bill K

Khéo léo. Tôi đã có xu hướng ném nó để mô phỏng một ngoại lệ thực tế.
Sathish

Không, vì Java 5 có một phương thức trên Thread để lấy ngăn xếp hiện tại dưới dạng một mảng của StackTraceElements; Nó vẫn không rẻ, nhưng rẻ hơn so với giải pháp phân tích ngoại lệ cũ.
Lawrence Dol

@Software Monkey Mặc dù tôi chắc chắn rằng nó phù hợp hơn, nhưng điều gì khiến bạn nói rằng nó rẻ hơn? Tôi cho rằng cơ chế tương tự sẽ được sử dụng, và nếu không, tại sao làm cho một cơ chế chậm hơn khi nó làm điều tương tự?
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

Đây là một phần của mã mà tôi đã thực hiện dựa trên các gợi ý được hiển thị trong chủ đề này. Hy vọng nó giúp.

(Vui lòng đưa ra bất kỳ đề xuất nào để cải thiện mã này, vui lòng cho tôi biết)

Quầy:

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);
    }

    (...)
}

Và đối tượng:

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);
    }
}

HOẶC LÀ

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

sử dụng phương pháp này: -

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

Người gọi phương thức ví dụ Mã ở đây: -

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();
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.