Java汎用翻訳汎用メソッド
8977 ワード
1.
汎用式の翻訳:プログラムが汎用メソッドを呼び出すときに、戻り値が消去されると、コンパイラは強制的なタイプ変換を挿入します.次の2つの文
元のタイプのメソッドgetFirst()の戻りはObjectに置き換えられますが、コンパイラはGregorianCalendarの強制タイプ変換を自動的に挿入します.コンパイラはこの文を2つの仮想マシン命令に翻訳し、バイトコードを挿入します.元のメソッドgetFirst()の呼び出しです.返されたObjectオブジェクトをGregorianCalendarに強制的に変換します.汎用ドメインにアクセスすると、バイトコードに強制的なタイプ変換も挿入されます.翻訳汎用メソッド:タイプ消去も汎用メソッドで発生します.たとえば、以前に定義した仮想マシンにも汎用メソッドはありません.汎用メソッドも「タイプ消去」を経験します.たとえば、 といういくつかの一般的な方法を定義します.
クラスアナライザを使用して分析した結果:
汎用メソッドのタイプ消去は2つの問題をもたらす.タイプ消去とマルチステートの衝突;2.メソッド署名の競合.構造が比較的複雑なクラスを見てみましょう.クラスDateIntervalは前に定義した汎用クラスPairを継承します.
Javaでのメソッド呼び出しは動的バインド方式を採用しており,多状態の特性を示すべきであることを知っている.サブクラス上書きスーパークラスのメソッドは、サブクラスを下にスーパークラスに変換した後も、上書き後のメソッドを呼び出すことができます.しかし、汎用クラスのタイプ消去には問題があり、Pairの元のタイプには方法があります.
DateIntervalのメソッド
public void setSecond(Date second)は、public void setSecond(Object second)メソッドを上書きしています.どうやってやったの?
Javaクラスアナライザを使用して分析した結果:
メソッド1とメソッド3は、ソースコードで定義されていません.コンパイラによって生成されるに違いありません.この方法をブリッジメソッド(bridgemethod)と呼び,本当にスーパークラスメソッドを上書きしたのはそれである.文pair.setSecond(date)は実際にメソッド1,public volatile void setSecond(Object)を呼び出し,このメソッドによりpublic void setSecond(Date)を呼び出す.この橋の方法の実際の内容は:
このような結果はオブジェクト向けのマルチステートの特性に合致し,方法の動的バインドを実現した.しかし、このようなやり方は私たちに錯覚をもたらし、public voidsetSecond(Date)が汎用クラスのpublic void setSecond(Object)を上書きしたと考えられ、DateIntervalに方法を追加すれば:
もう一度運転して、今回の結果の違いを観察してください.面白いでしょう.私が使っているNetbeanIDEは、この方法の前に@Overrideを付けるようにヒントを与えていません.setSecond(Date)方法の前に@Overrideの注釈を加えるようにヒントを与えます.今私たちは知っています.これはただの仮象です.メソッド3もコンパイラによって生成されるブリッジメソッドであり,マルチステートを実現するためであることが分かった.メソッド消去による2つ目の問題は、コンパイラによって生成されたブリッジメソッドpublicvolatile javaである.lang.Object getSecond()メソッドとpublic java.util.DategetSecond()メソッドは、メソッド署名の観点から2つの全く同じメソッドであり、それらはどのように共存することができますか?Javaコードを自分で作成する場合、このようなコードはコンパイラのチェックに合格できませんが、仮想マシンはパラメータタイプと戻りタイプで方法を決定するため、コンパイラは汎用的なマルチステートを実現するために自分がこの「合法的ではない」ように見えることを許可します.
補足説明:JDK 1から.5から、1つのメソッドが別のメソッドを上書きするときに、より厳密な戻りタイプを指定することができ、そのメカニズムも同様に使用されるブリッジメソッドです.例:
テキストリンク:http://blog.sina.com.cn/s/blog_44c1e6da0100coxb.html
汎用式の翻訳:プログラムが汎用メソッドを呼び出すときに、戻り値が消去されると、コンパイラは強制的なタイプ変換を挿入します.次の2つの文
Pair birthdays =...;
GregorianCalendar first =birthdays.getFirst();
元のタイプのメソッドgetFirst()の戻りはObjectに置き換えられますが、コンパイラはGregorianCalendarの強制タイプ変換を自動的に挿入します.コンパイラはこの文を2つの仮想マシン命令に翻訳し、バイトコードを挿入します.元のメソッドgetFirst()の呼び出しです.返されたObjectオブジェクトをGregorianCalendarに強制的に変換します.汎用ドメインにアクセスすると、バイトコードに強制的なタイプ変換も挿入されます.
public class ArrayAlg{
publicstatic T getMiddle(T[]t){
System.out.println(" ");
return t[t.length/2];
}
publicstatic Pair minmax(T[]ts){
if(ts == null || ts.length == 0){
return null;
}
T min = ts[0];
T max = ts[0];
for(int i = 0;i length;i++){
if(min.compareTo(ts[i]) >0){
min = ts[i];
}
if(max.compareTo(ts[i]) <0){
max = ts[i];
}
}
return new Pair(min,max);
}
クラスアナライザを使用して分析した結果:
publicstatic int getMiddle(int[]);
publicstatic Pair minmax(java.lang.Comparable[]);
汎用メソッドのタイプ消去は2つの問題をもたらす.タイプ消去とマルチステートの衝突;2.メソッド署名の競合.構造が比較的複雑なクラスを見てみましょう.クラスDateIntervalは前に定義した汎用クラスPairを継承します.
public class DateInterval extends Pair<Date> {
publicDateInterval(Date first, Date second){
super(first, second);
}
@Override
public void setSecond(Date second) {
super.setSecond(second);
}
@Override
public Date getSecond(){
return super.getSecond();
}
public static void main(String[] args) {
DateIntervalinterval = new DateInterval(new Date(), newDate());
Pair pair =interval;// ,
Date date = new Date(2000, 1, 1);
System.out.println(" :"+pair.getSecond());
System.out.println("set :"+date);
pair.setSecond(date);
System.out.println(" pair.setSecond(date) :"+pair.getSecond());
}
}
Javaでのメソッド呼び出しは動的バインド方式を採用しており,多状態の特性を示すべきであることを知っている.サブクラス上書きスーパークラスのメソッドは、サブクラスを下にスーパークラスに変換した後も、上書き後のメソッドを呼び出すことができます.しかし、汎用クラスのタイプ消去には問題があり、Pairの元のタイプには方法があります.
public void setSecond(Object second);
DateIntervalのメソッド
public void setSecond(Date second);
私たちの本意はPairのsetSecondメソッドを上書きしたいと思っていますが、メソッド署名から見ると、これは完全に2つの異なるメソッドであり、タイプ消去はマルチステートと衝突しています.実際の状況は?DateIntervalのmainメソッドを実行すると、public void setSecond(Date second)は、public void setSecond(Object second)メソッドを上書きしています.どうやってやったの?
Javaクラスアナライザを使用して分析した結果:
public class DateInterval extends Pair{
//
public DateInterval(java.util.Date,java.util.Date);
//
public void setSecond(java.util.Date);
public volatile voidsetSecond(java.lang.Object);// 1
public java.util.DategetSecond( );// 2
public volatile java.lang.Object getSecond();// 3, 1 ?
public static void main(java.lang.String[]);
}
メソッド1とメソッド3は、ソースコードで定義されていません.コンパイラによって生成されるに違いありません.この方法をブリッジメソッド(bridgemethod)と呼び,本当にスーパークラスメソッドを上書きしたのはそれである.文pair.setSecond(date)は実際にメソッド1,public volatile void setSecond(Object)を呼び出し,このメソッドによりpublic void setSecond(Date)を呼び出す.この橋の方法の実際の内容は:
public void setSecond(Objectsecond){
this.setSecond((java.util.Date) second );
}
このような結果はオブジェクト向けのマルチステートの特性に合致し,方法の動的バインドを実現した.しかし、このようなやり方は私たちに錯覚をもたらし、public voidsetSecond(Date)が汎用クラスのpublic void setSecond(Object)を上書きしたと考えられ、DateIntervalに方法を追加すれば:
publicvoid setSecond(Object obj){
System.out.println(" !");
}
もう一度運転して、今回の結果の違いを観察してください.面白いでしょう.私が使っているNetbeanIDEは、この方法の前に@Overrideを付けるようにヒントを与えていません.setSecond(Date)方法の前に@Overrideの注釈を加えるようにヒントを与えます.今私たちは知っています.これはただの仮象です.メソッド3もコンパイラによって生成されるブリッジメソッドであり,マルチステートを実現するためであることが分かった.メソッド消去による2つ目の問題は、コンパイラによって生成されたブリッジメソッドpublicvolatile javaである.lang.Object getSecond()メソッドとpublic java.util.DategetSecond()メソッドは、メソッド署名の観点から2つの全く同じメソッドであり、それらはどのように共存することができますか?Javaコードを自分で作成する場合、このようなコードはコンパイラのチェックに合格できませんが、仮想マシンはパラメータタイプと戻りタイプで方法を決定するため、コンパイラは汎用的なマルチステートを実現するために自分がこの「合法的ではない」ように見えることを許可します.
補足説明:JDK 1から.5から、1つのメソッドが別のメソッドを上書きするときに、より厳密な戻りタイプを指定することができ、そのメカニズムも同様に使用されるブリッジメソッドです.例:
public class A{
public ListgetList(){
return null;
}
}
public class ASub extendsA{
@Override
publicArrayList getList(){
return null;
}
}
ASub , :
public class ASub extendsA{
//
//
public ASub();
//
publicjava.util.ArrayList getList( );
publicvolatile java.util.List getList( );
}
テキストリンク:http://blog.sina.com.cn/s/blog_44c1e6da0100coxb.html