最近、私はSpring Frameworkのソースコードを読んでいます。私が理解できないことはここに行きます:
public Member getMember() {
// NOTE: no ternary expression to retain JDK <8 compatibility even when using
// the JDK 8 compiler (potentially selecting Java.lang.reflect.Executable
// as common type, with that new base class not available on older JDKs)
if (this.method != null) {
return this.method;
}
else {
return this.constructor;
}
}
このメソッドは、org.springframework.core.MethodParameter
クラスのメンバーです。コードはわかりやすく、コメントは難しいです。
注:JDK 8コンパイラを使用する場合でも、JDK <8互換性を保持するための3項式はありません(潜在的に
Java.lang.reflect.Executable
を選択し、新しいベースクラスは古いJDKでは使用できません)
このコンテキストで三項式を使用することとif...else...
コンストラクトを使用することの違いは何ですか?
オペランドのタイプを考えると、問題がより明確になります。
this.method != null ? this.method : this.constructor
型として、両方のオペランドの最も特殊な共通型、つまり両方のthis.method
およびthis.constructor
。
Java 7これは Java.lang.reflect.Member
、ただしJava 8クラスライブラリは新しいタイプを導入します Java.lang.reflect.Executable
これは、一般的なMember
よりも特殊化されています。したがって、Java 8クラスライブラリを使用すると、3項式の結果タイプはExecutable
ではなくMember
になります。
Java 8コンパイラの一部の(プレリリース)バージョンは、三項演算子のコンパイル時に生成コード内でExecutable
への明示的な参照を生成したようです。これにより、クラスのロードがトリガーされます。 、したがって、ClassNotFoundException
は8以上のJDKに対してのみ存在するため、クラスライブラリ<JDK 8で実行する場合、実行時にExecutable
が順番になります。
この回答 でTagir Valeevが指摘したように、これは実際にはJDK 8のプレリリースバージョンのバグであり、その後修正されているため、if-else
回避策と説明コメントは廃止されました。
追記:このコンパイラのバグは、Java 8.より前に存在していたという結論に達するかもしれません。ただし、バイトOpenJDK 7によって生成された3進コードは、OpenJDK 8によって生成されたバイトコードと同じです。実際、式のタイプは実行時にまったく言及されず、実際にはコードは追加のチェックなしでテスト、ブランチ、ロード、リターンのみですしたがって、これは(もう)問題ではなく、実際にJava 8の開発中に一時的な問題であったように見えます。
これは quite old commit 2013年5月3日、公式のJDK-8リリースのほぼ1年前に導入されました。当時、コンパイラは大いに開発中であったため、このような互換性の問題が発生する可能性がありました。おそらく、SpringチームはJDK-8ビルドをテストし、実際にはコンパイラーの問題であるにもかかわらず、問題の修正を試みただけだと思います。 JDK-8の公式リリースでは、これは無関係になりました。これで、このコードの三項演算子は期待どおりに機能します(コンパイルされた.classファイルのExecutable
クラスへの参照は存在しません)。
現在、JDK-9でも同様のことが起こります。JDK-8でうまくコンパイルできるコードの一部は、JDK-9 javacで失敗します。そのような問題のほとんどはリリースまで修正されると思います。
主な違いは、if
else
ブロックがstatementであるのに対し、三項(Javaではconditional演算子としてよく知られている) 式です。
statementは、いくつかの制御パスで呼び出し元に対してreturn
などのことを実行できます。 expressionは、割り当てで使用できます。
int n = condition ? 3 : 2;
したがって、条件の後の3項の2つの式は、同じ型に強制変換可能である必要があります。これは、Javaで特に奇妙な効果を引き起こす可能性があります。特に自動ボックス化および自動参照キャストで-これは投稿コードのコメントが参照しているものです。あなたの場合の式の強制はJava.lang.reflect.Executable
タイプ(最も特殊化されたタイプ)であり、古いバージョンのJavaには存在しません。
コードが文のような場合はif
else
ブロックを使用し、式のような場合は3項を使用する必要があります。
もちろん、ラムダ関数を使用する場合、if
else
ブロックを式のように動作させることができます。
三項式の戻り値の型は、Java 8。
キャストが書けなかった理由がわかりにくい。