Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

ソースコードからクラスやメソッドなどの定義を抽出したい。

eclipseにあるように開いているソースコードからクラスやメソッドなどの定義を抽出してツリー構造で表示したいと思っているのですが、どうすればできるかがよくわかりません。
それぞれの定義が以下のパターンで構成されるであろうことはわかるのですが、省略可能な部分があったり型名や名前は定義によって様々なのでどうすればいいでしょうか?

クラスの定義
["public "]class〜{

メソッドの定義
["public "|"public static "|"private "|"protect "][型名]〜(){

変数などの定義
["public "|"public static "|"private "|"protect "]型名〜;

([]省略可能)

14

回答

95714

閲覧

14件の回答

評価

0

クラスがpublicだけだったり、publicとpublic staticを
同列に並べてる辺り、実はアクセス制御についてちゃんと
理解できてないのでは?

評価

0

>実はアクセス制御についてちゃんと理解できてないのでは?

そうかもしれません。
Javaの授業では無駄にstaticを付けることで有名らしい先生に習っていたもので、privateやprotectの使い方を学んだ覚えがありません。
私自身はstaticにしなくてもいいところはstaticにしないようにするようにしています。
そして、publicなどはデフォルトで書かれたりしなければ自らの意志では基本書いていません。
privateやprotectは存在を知っているだけで使ったことないように思います。

クラスにエンクロージング型があることを忘れてました。
それならpublic以外が来ることもあるでしょうね。

自分のために作るエディターにeclipseのような定義のツリーを表示できたりしたら便利かもと思っています。
その前段階としてそれぞれの定義パターンってだいたいあんな感じかな?と思って書いてみたのがあれです。
でも、実際のあらゆるパターンとは多少違ってしまっているのかもしれません・・・

評価

0

まあ、自分のコードに限定して使うというなら、それく
らいでもいいかも知れない。
人によってはstatic publicという順で書いてるが、自
分のコードというならこれも考えなくていい。

finalは使ったことがないか? クラスやメソッドは使わ
ない人もいるが、最低でも定数には使ってると思うが。

あとはabstractとinterface、enum、extendsと
implements、それにthrowsくらいか、一覧の情報として
必要十分と言えば。

評価

0

staticの位置はpublicの前でもいいんですね。
public static 〜という書き方ばかりしていて、そういう書き方ができることは考えていませんでした。

finalは使ったことないです。
変数を定数として使ったことがない気もします。

extendsやimplementsは普通に使ったことありますが、これらも省略可能というか書かない場合もありますから、そこは〜に略して書きました。
クラスの定義の抜き出しはclassがある行のタブ抜いた先頭から{の前までを抜き出せればいいかなと思っています。

abstractは使ったことありません。
ListenerでいらないメソッドがあればAdapterのエンクロージング型クラス作っちゃって必要なメソッドだけオーバーライドしてるもので。

implementsできるのがinterfaceでしたっけ?
自分でinterface作ったことはありません。
enumは名前くらいしか知らないです。

throwsは書かずにtry-catch文を書いてます。
とあるメソッドで発生する可能性のあるエラーをメソッドを呼び出し元メソッドに通知したいと思ったことがないので。

初めのうちから私以外の人も使えるようになんて考えるといろいろと面倒な部分もあると思っていたので、最低限自分が使う上で自分が便利だと思うものを作り上げようと思っています。

評価

0

メソッド内部でtry〜catchする場合、catchせずにthrows
にする場合、それぞれ意味があってそうするのであって、
単に好みで使い分けるものではない。

Javaのメソッドの基本的な考え方は、「異常系は
Exception」だ。

自分のためにしかプログラムを作らないならとやかく言わ
ないが、そうでないなら、そういった辺りも少し意識して
みるといい。

評価

0

>Javaのメソッドの基本的な考え方は、「異常系は
Exception」だ。

try-catch文はeclipseが囲めというから囲む程度で、たとえばFileWriterがIOExpectionをthrowするとか言うのは全然覚えてません。
(そういうのは言われるからでなく覚えて自分から書けるようになる方がいいんでしょうけど。)

まだ学生の身分で他人に見せることを意識してコードを書いたことがありませんが、就職してプログラマーになることを考えたらそういうことを気人と意識しなくてはなりませんね。

評価

0

>eclipseが囲めというから
いや、それと同時にthrowsを付けるオプションも、提示さ
れているはずだが?

選ぶのはクラスをデザインする側であり、そのための知識
を身につけていく必要がある。
別にすぐさまできるようになれ、なんてことは言わない。
「こうしたらエラーがなくなった、だからこうする」って
のをいつまでも続けてるのはダメだとだけ、思っておけば
いい。

評価

0

確かにthrowsも提示されますが、選んだことないです。
try-catch文で囲んでいる範囲もあっているかどうか。
今度そういうコードの書き方の規則をきちんと勉強しないといけませんね。

評価

0

以下のコードで一応関数やメソッドの定義部分を抽出することができました。

void set(String code){
    String[] str=code.split("\n");
    Vector<String> codes=new Vector<String>();
    for(int n=0;n<str.length;n++){
        codes.add(str[n]);
    }
    Vector<Integer> tab=new Vector<Integer>();
    DefaultMutableTreeNode top=null;
    for(int n=0;n<codes.size();n++){
        if(codes.get(n).indexOf("class")!=-1){
            tab.add(codes.get(n).lastIndexOf("\t"));
            top = new DefaultMutableTreeNode(codes.get(n).substring(0, codes.get(n).indexOf("{")));
            list.put(codes.get(n).substring(0, codes.get(n).indexOf("{")), n);
            codes.remove(n);
            n--;
            createNodes(tab, top, codes);
            break;
        }
        else{
            codes.remove(n);
            n--;
        }
    }
    tree=new JTree(top);
    setViewportView(tree);
}

private void createNodes(Vector<Integer> tab,DefaultMutableTreeNode tree, Vector<String> codes) {
    for(int n=0;n<codes.size();n++){
        if(codes.get(n).indexOf("class")!=-1){
            tab.add(codes.get(n).lastIndexOf("\t"));
            DefaultMutableTreeNode subtree = new DefaultMutableTreeNode(codes.get(n).substring(codes.get(n).lastIndexOf("\t")+1, codes.get(n).indexOf("{")));
            codes.remove(n);
            n--;
            createNodes(tab, subtree, codes);
            list.put(codes.get(n).substring(0, codes.get(n).indexOf("{")), n);
            tree.add(subtree);
        }
        else if(tab.size()>0 && codes.get(n).lastIndexOf("\t")==tab.get(tab.size()-1)){
            tab.remove(tab.size()-1);
            codes.remove(n);
            n--;
        }
        else if(codes.get(n).indexOf("{")!=-1 && codes.get(n).indexOf("else")==-1 &&
                codes.get(n).substring(codes.get(n).lastIndexOf("\t"), codes.get(n).indexOf("{")).indexOf(" ")!=-1){
            DefaultMutableTreeNode subtree = new DefaultMutableTreeNode(codes.get(n).substring(codes.get(n).lastIndexOf("\t")+1, codes.get(n).indexOf("{")));
            tree.add(subtree);
            list.put(codes.get(n).substring(codes.get(n).lastIndexOf("\t")+1, codes.get(n).indexOf("{")), n);
            codes.remove(n);
            n--;
        }
        else{
            codes.remove(n);
            n--;
        }
    }
}

あとはとりあえず変数や配列の定義が抽出できればいいのですが、配列は何となくできそうですが変数のほうが見当もつきません。
もし何かアイデアがあれば教えてください。

評価

0

メソッドのとこelse if対策はしたけれどforやwhile対策をするのを忘れてました・・・;
他にも問題がありそうな気もするのでメソッドの部分はもう一度考え直すことにします。

評価

0

限定したパターンの変数宣言だけ解析すると仮定しま
す。例えば以下のパターン:

 型前 [ "<" 型名 ">" ] "[]"* 変数前 { "=" | ";" } 
...

 ('*'は0回以上の繰り返し、'{A|B}'はAかBのどちらか
のパターンという意)

行の先頭から一文字ずつ調べていき上のパターンに合致
するかどうかを調べるメソッドを書いてそのメソッドを
呼び出してその行が変数宣言行かどうか判断するという
戦略でいかがでしょう。(ちなみに空白文字は上のパタ
ーンには一々かいてません)
実際に処理を書いてみるとわかると思いますが相当煩雑
です。根気さえあればなんとかなるとは思いますが。
ちなみにそれと同じことは java.util.regex.Pattern 
でかなり少ない行数で記述できます。正規表現がとっつ
きにくいかもですが挑戦されてみるのもいいかも知れま
せん。


評価

0

使う型が限定されていればがんばればなんとかと思ってましたけど、限定されていないというかアウトライン解析をしたいと思っているソースで使っている型の種類は今後増えるので、そうもいかないんですよね。
型が決まっていればJavaCCで構文解析してみるなんてことも考えましたが。

評価

0

JavaCCを使う方法が正統的な方法になるかと思います。字
句に分解して構文パターンを調べるという普通のコンパイ
ラーと同レベルの機能が実現できますので。
ただJavaCCは言語解析の知識がそれなりに必要なので挑戦
するならガッツで頑張ってください。

蛇足ですけど、ソースをjavacでコンパイルしてしまいク
ラスファイルをロードしてreflection機能で一覧出すとか
やるとエラーのあるソースはNGですけど、煩雑な構文解
析問題を避けて通れる点で一番簡単な気はします。

評価

0

JavaCCで日本語で書けるプログラミング言語を作るのが一番の目的なので、JavaCCについては現在勉強中です。
最近はそのJavaCCなどをコンパイルするのに便利なツールを作ろうとしていて、できるならJavaファイル(など)のアウトライン解析ができたら便利かなと思ってその機能を実装したいと考えています。
抽出したい定義のパターンがある程度定まっていればJavaCCを使ってなんとかできるかもしれませんが、そこまで定まってはいないもので。

reflectionについては調べてみます。
一度javaファイルをコンパイルしておかないと使えないというのがネックですが、今自分が作っているものよりは使えそうですね。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。