◆PROCESSING 逆引きリファレンス
カテゴリー:制御系
クラス名、メソッド名を取得するには
【解説】
プログラムを開発していると、いま動作しているクラスの名前やメソッド名を知りたくなることがあります。
例えば何かのエラーが発生してログを採取する時に、「どのクラス」の「どのメソッド」がエラーとなったのかを明示するような場合でしょうか。
PROCESSINGはJavaをベースにした言語ですので、Javaと同じ手法が利用可能です。
Javaで実行中のクラス名やメソッド名を取得する方法については、下記サイト様などに詳しく解説されています。
- Quita様 munieruさんの記事 様
- Yukiの枝折 様
- No Programming, No Life 様
本記事では上記サイト様の情報を元に、それをPROCESSING上で試してみました。
クラス名、メソッド名を取得する代表的な方法には、「実行時クラスから取得する」方法と「スタックトレースを利用する」方法の2種類があります。
【構文】
●実行時クラスから取得する(Java1.5以降)
String className = new Object(){}. getClass(). getEnclosingClass(). getName() ;
String methodName = new Object(){}. getClass(). getEnclosingMethod(). getName() ;
●スタックトレースを利用する(Java1.5以降)
String className = Thread.currentThread(). getStackTrace()[n]. getClassName() ;
String methodName = Thread.currentThread(). getStackTrace()[n]. getMethodName() ;
className :命令実行時のクラス名
methodName:命令実行時のメソッド名
※nはスタックの位置を指す値です。
【注意】
「実行時クラスから取得する」方法は、メソッド名を取得するのにオブジェクトをNewする必要があるため、非常に重たい処理になります。
またその特性上、メソッド名を取得する部分は独立した関数にする( new Object()する部分を部品(関数)にして利用する)のは困難でしょう。
「スタックトレースを利用する」方法では、クラス名やメソッド名以外にも情報を取得する事が可能です。
(あくまで相対論ですが)こちらの方が「実行時クラスから取得する」方法に比べて軽く、情報を取得する部分を関数にする事が可能ですので、使い勝手が良いかもしれません。
getStackTrace()[n] の nは、スタックの階層位置を示しています。
Thread.currentThread(). getStackTrace()[n]では、n = 0 はスタックトレースを採取するスレッド(java.lang.Thread)のgetStackTrace()命令の情報です。
よって n = 1 がgetStackTrace()命令を実行したメソッドの情報になります。
もしも、getStackTrace()命令でメソッド名やクラス名を取得する処理を部品(関数)にするのであれば、何番目のスタックからメソッド名を抜き出すべきか間違わないようにしないといけません。
今回はクラス名やメソッド名を取得する例としてログ採取を取り上げましたが、真面目にログ採取を行うのであれば、Loggerやlog4j などの専門のロガーを利用した方が良いでしょう。
【関連記事】
- なし
サンプルプログラム
実行時クラスから取得する例:
1 2 3 4 5 6 7 8 9 10 11 12 |
void setup(){ size(100,100); //情報取得用にオブジェクトを生成する String clsName = new Object(){}.getClass().getEnclosingClass().getName(); String mtoName = new Object(){}.getClass().getEnclosingMethod().getName(); println( "クラス名:" + clsName ); println( "メソッド名:" + mtoName ); noLoop(); } void draw(){ } |
本例では setup() 関数内部でオブジェクトを生成し、クラス名とメソッド名を取得しています。
PROCESSINGの場合、特別なことをしない限り setup()関数が含まれるクラスはスケッチファイルの名前と同じになります。よって、上記のスケッチファイル名は sketch_170323a.pde です。
スタックトレースを利用する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup(){ size(100,100); printInfo( "----setupから呼び出し----" ); noLoop(); } void draw(){ printInfo( "----drawから呼び出し----" ); } void printInfo( String msg ){ StackTraceElement[] ste = Thread.currentThread().getStackTrace(); String clsName = ste[2].getClassName() ; String mtoName = ste[2].getMethodName(); println( msg ); println( "クラス名:" + clsName ); println( "メソッド名:" + mtoName ); } |
クラス名とメソッド名を表示する部分を関数にしました。
setup() と draw() から呼び出していますが、それぞれのメソッド名が表示できている事に注目してください。
またスタックトレースの階層には 2 を指定しています。この例では
0:getStackTrace()
1:printInfo()
2:printInfo()を呼び出したメソッド
になるためです。
setup()までのスタックを表示する例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup(){ size(100,100); printInfo( ); noLoop(); } void draw(){ } void printInfo( ){ StackTraceElement[] ste = Thread.currentThread().getStackTrace(); for( int i = 0; i < ste.length; i++ ){ String clsName = ste[i].getClassName() ; String mtoName = ste[i].getMethodName(); println( "(" + String.valueOf(i) + ") クラス名:" + clsName + "/メソッド名:" + mtoName ); } } |
setup()関数が、どのような順路で呼び出されているのか表示させてみました。
PROCESSING3.3では、setup()関数は processing.core.PSurfaceNoneクラスに含まれるAnimationThread()クラスより、スレッドとしてrun()される事で呼び出されてきた事がわかります。
一般的なスタックトレースでは、大元の呼び出しは main() 関数になります。
PROCESSINGの場合は、setup()関数を含む自分たちが作成したクラスがAnimationThread()クラスからスレッドとして起動されているため、このように表示されるのです。
本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。