アノテーション

かなり前に、はじめてSpring Bootの案件に入った際に、マイコン脳の老プログラマが最後まで腑に落ちなかったのはアノテーションだった。

簡単に言うと「初期化されていないメンバーになんで値が入っているのか(Autowired)」「存在しないメソッドが何で呼び出せるのか(Lombok,JPA)」

便利なのは確かであったが当時はそういう約束事だと考えて進めるしかなかった。今だって中の詳細ロジックが読めている訳ではない。ただ細部はウソでもよいので自分が納得できる理由が説明できておかないと解決困難な問題を追跡する際に当て外れな部分の調査に負荷が発生するので、問題解決の枝刈りをするためにも「結局何なのか」を自分なりに理解しておく必要があった。

ネットでごそごそ調べた調べた結果、アノテーションはその名の通り「単なるラベル」だった。

プログラムのソースのメソッドやクラス、メンバ変数の位置にラベルでマークを付けるもの。

ラベルがどう使われるかはいくつか種類があり、

  1. コンパイル時に探すことができて、jar出力結果を変える
  2. jarの中にそのままラベルを付けて、実行時に変数やメソッドに位置を探せるもの
実行時ラベルの例

で、ツール/フレームワーク側でラベルを探索することで、よい意味でのインチキめいたハックをしている訳だ。

とりあえず自身としてはそう理解できていればよいと考えた。細部はAutowiredやLombok等で。

2020/06/28付近

昼マクド、ケーキ屋、午後少し書く方向、ニンテンドーオンライン1W、お酒は検討、ブログは比較的調整、レシート整理優先、その後url csv

→レシート整理完、url csvは思ったより有効な情報がなかった。 目立ったのは、バイトコード関係の調査とElm関係の調査→会計ツールとバイトコード関係に切替

JVMバイトコード

Javaの実行時中間言語。MSの中間言語(MS IL)と並んで有名な中間言語。

自分らの世代で考えると本当にマシン語/アセンブラと同じと考えてよい。基本命令さえ把握すれば全然普通に読める。

普段このバイトコードでプログラムを読む必要はまったくないが、気分的に「いざとなればこのレベルで読めば全部分かる」と思い込んでおけば後々の今風技術にもひるまずに済む。

一部高級言語/オブジェクト指向言語固有命令と思われるものは出てくるが、それはそういうものでJavaマシン側でほどよく処理してくれていると考えれば問題ない(monitor,throw,invokevirtualなど)。

  • 解析環境
  1. intelliJ IDEAにjclasslib Bytecode viewer (https://plugins.jetbrains.com/plugin/9248-jclasslib-bytecode-viewer) プラグインをインストールする。
  2. Java,Scala等でサンプルのjavaコードを書く。よくあるサンプルプロジェクトみたいなものでもよい。
  3. 実行する(つまりjarがビルドされている)
  4. 該当ソースを選んで開く。その状態でメニュー View > Show bytecode with jclasslib を選ぶ。
  5. jar内サマリーとそのクラスのバイトコード解析ウィンドウが出る。

開いているファイルのクラスのバイトコード一式の表示が出る

  • Constant Pool 定数一式
  • Field メンバー変数
  • Method メソッド定義 Code部にバイトコードがアセンブラ風に表示される

あたりが分かればあとは何かのバイトコードの仕様とアセンブラ知識があればなんとなくは分かる。

元Javaソースとバイトコード出力結果を並べてみる。

public class SimpleJava { 
  public void addTest(int num1,int num2)  {
    int sum = num1 + num2;
    System.out.println(Integer.toString(sum));
  }
}
(引数num1はローカル変数1に、num2はローカル変数2に入っているとする) 
0 iload_1    (ローカル変数1から整数を取り出し、スタックにプッシュする)
 1 iload_2   (ローカル変数2から整数を取り出し、スタックにプッシュする)
 2 iadd      (スタックに詰まれた2つのデータを2つプルして取り出し、それを整数として加算し、スタックに再プッシュする=つまりスタックは2つの数字の代わりに加算した数字になる)
 3 istore_3  (スタックから整数をプルし、ローカル変数3に入れる)
 4 getstatic #8 <java/lang/System.out> (外部変数System.out出力端末番号を取り出しスタックにプッシュする)
 7 iload_3   (ローカル変数3から数字を取り出し、スタックにプッシュする=この時点でスタックには、System.outと加算した数字が詰まれる)
 8 invokestatic #9 <java/lang/Integer.toString> (外部の手続きInteger.toStringを呼び出す。恐らく中でスタックをプルして加算した数字を取り出し、文字列配列変換して、そのポインタをプッシュする)
11 invokevirtual #10 <java/io/PrintStream.println> (外部の手続きprintlnを呼び出す。スタックに詰まれていたSystem.outと変換した文字列ポインタを取り出し、プリント処理をする)
14 return     (戻る)

完全にスタックベースで計算するアセンブラである。

これでわかったつもりになって問題ない。

目的と書きたいこと

コンピュータをマシン語的、フローチャート/手続き型的に理解していて、なんとかオブジェクト指向の端っこくらいは理解したが、その先の今風技術がとっつきにくい人に 、なんとなく分かったと思わせて安心させるための念仏を短く作る。

  • マシン語的 = レジスタ、メモリ、プログラムカウンタ、インデックスレジスタなど
  • フローチャート/手続き型的=let ,if ,for/while, gotoなど
  • オブジェクト指向の端っこ=なんとなくclassはinterfaceは書くけど概念や哲学と言われると少し怪しい
  • 今風技術がとっつきにくい人=自分など

調べたい/書きたい項目

  • JVM
  • アノテーション
  • Autowired
  • lombok
  • 名付けのルール
  • MVC
  • 関数型
  • 非同期
  • カリー化
  • Option
  • map/for/flatMap
  • Either
  • Future
  • EitherT
  • React

2020/06/21付近週末

思いついてjvmバイトコードの勉強しなおし。外出予定は普通。久しぶりに布団コインランドリー。続くかどうかはわからんがやり始める価値は認識。チーズケーキも悪くない。