コンパイラ課題

そろそろやばくなってきたので提出してみようと意気込んでみた。
で、課題の中で各言語処理系における型多相の扱いについて調べるものがあったので、javacについて実際にやってみることにした。

import java.util.*;
class Main{
	public static void main(String [] argv){
		LinkedList list = 
                         new LinkedList();
		list.add(new Integer(1));
		Integer i = list.getFirst();
		System.out.println(i);
	}
}

これが元のソース。で、これをjavacがどう処理しているかといえば、例えばlist.getFirst()の部分は(Integer)list.getFirstのように勝手に置換しているというのは有名な話。
でもまあ、それだけなのかどうなのかはやってみなくてはわからないということで、手で書き直してみる。

import java.util.*;
class Main{
	public static void main(String [] argv){
		LinkedList list = new LinkedList();
		list.add(new Integer(1));
		Integer i = (Integer)list.getFirst();
		System.out.println(i);
	}
}

これをコンパイルするには-Xlint:uncheckedオプションをつける必要がある。それでも警告は出るのだけれど。

> javac Main.java -Xlint:unchecked
Main.java:5: 警告: [unchecked] raw 型 java.util.LinkedList 
           のメンバとしての add(E) への無検査呼び出しです。
                list.add(new Integer(1));
                        ^
警告 1 個

で、これを二つともコンパイルしてdiffを取ってみると、見事に何も出ない。
ここで終わると面白くないので、さらにちょっと変えてみる。

import java.util.*;
class Main{
	public static void main(String [] argv){
		LinkedList list = new LinkedList();
		list.add(1);
		Integer i = list.getFirst();
		System.out.println(i);
	}
}

今度はboxing処理の実験。list.addの引数に、new Integer(1)ではなくてただの1を与えてみる。すると、今度はdiffで違うと言われる。
この理由について、よくわからなかったのだけれども、吐かれたclassファイルを読んでみて理解できた。1からIntegerの1に変換するときに使われるのは、newではなくてvalueOfメソッドのようだ。実際、それでdiffを取ってみたところ同じだと言われた。
まあ、この仕様自体は、newだろうとvalueOfだろうと困らないんだけれど。