Java汎用翻訳汎用メソッド

8977 ワード

1.
汎用式の翻訳:プログラムが汎用メソッドを呼び出すときに、戻り値が消去されると、コンパイラは強制的なタイプ変換を挿入します.次の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