主にブクマにいただいたコメントへの回答です。
t_yano ん?どうなんだろ。静的コンパイラ言語としては、実行バイナリを作るコンパイル段階でそういうエラーを出すことはOKだと思うんだけど.../shuyoに説明されて、他人のclassオーバーライドしてこれが出たら微妙なだとおもた
yojik プログラム的に隠蔽してるからといって、開発者からも分からなくする必要は無いと思います。むしろコンパイル時は積極的に情報開示するべき。
shuji_w6e えっ? アクセス制御であって、スーパークラスの契約の一部(private field)が伝わる事は良い事だと思う
コメントをいただいて気づいたのですが、
- アクセス制御という意味での private
- その存在自体が外部に漏れてはいけないという意味での private
なのかで話が変わってきますね。自分としては shuyo さんが仰っていたのは後者の意味で、Java における private は前者の意味だと受け取りました。Java では (仕様で決まっている) クラスファイルを解析したり、(標準ライブラリに含まれる) リフレクションを使えば、private なメンバの存在も容易に知れるのだから、存在を private にする意味もそれほどないかなと思います。
アクセス制御の private と考えれば、存在自体は public でもいいことになるから、(ご指摘の通り) コンパイル段階で「アクセスできない情報にアクセスしようとしている」というエラーを出すのはむしろ当然のように思えます。
Nagise コンパイルしてから親をprivateにした場合は実行時例外だったと思うのだけど。後で確認する
tomorrowkey ほんとにアクセスできた。なんてこったい
Akineko 試してみたら実行時例外(IllegalAccessError)でました。[version:1.6.0_14]
とりあえず手元の Windows に 5 と 6 を入れて、5 のコンパイラで生成したクラスを 5 と 6 の実行環境でそれぞれ実行させてみたところ、5 ではアクセスできて、6 では java.lang.IllegalAccessError が投げられました。*1
% /usr/local/java5/bin/java -version java version "1.5.0_20" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_20-b02) Java HotSpot(TM) Client VM (build 1.5.0_20-b02, mixed mode, sharing) % /usr/local/java6/bin/java -version java version "1.6.0_15" Java(TM) SE Runtime Environment (build 1.6.0_15-b03) Java HotSpot(TM) Client VM (build 14.1-b02, mixed mode, sharing)
public class Parent { public int val; // Child をコンパイル後に private に変更 → Parent だけ再コンパイルして整合性を失わせる。 public Parent(int val) { this.val = val; } } public class Child extends Parent { public Child(int val) { super(val); } static public void main(String[] args) { Child c = new Child(2); System.out.println(c.val); } }
% /usr/local/java5/bin/java Child 2 % /usr/local/java6/bin/java Child Exception in thread "main" java.lang.IllegalAccessError: tried to access field Parent.val from class Child at Child.main(Child.java:8)
さすがにこれ以上は JVM の実装のソースを読まないとわからないような気がします...。