JAVA|汎用知識点全面総括—JAVA核心技術巻第一第五版を参考する

8269 ワード

汎用的な定義
  • 汎用クラス
  • を定義する
    public class Demo1 {
        public static void main(String[] args) {
            Pair pair = new Pair<>();
            pair.first = 1;
            pair.second = 2;
            pair.third = "3";
        }
    }
    
    class Pair {
        public T first;
        public T second;
        public V third;
    }
    

    2.汎用メソッドの定義(コンパイラが推測できない場合を除き、呼び出し時にタイプを指定する必要はありません)
    class Methods{
        public static  T getName(T info) {
            return info;
        }
    }
    Methods methods = new Methods<>();
    Object o = Methods.getName(5);
    System.out.println(""+ o.getClass().getSimpleName());//  Integer
    

    汎用クラスで汎用メソッドを定義する場合、汎用メソッドはクラスの汎用タグと一致しない必要があります.そうしないと、コンパイラは警告を求めますが、実際のマッチングは汎用メソッドが実行されている場合の検出タイプに準じます.
    class Methods{
         public   T getName(T info) {
             return info;
         }
     }
    

    汎用型の限定
  • キーワードextendsを使用する;
  • 複数の使用可能&分割があり、入力されたパラメータタイプはextendsの後のタイプを同時に満たす必要がある.
  • extendsの後ろにはクラス、抽象クラス、インタフェースがあります.
  • extendsの後ろにあるタイプのラベルインタフェース(メソッドインタフェースなし)を最後に置くことを推奨します.
  • class Animal implements Common{
        void speak(){
            System.out.println("speak");
        }
    
        @Override
        public void who() {
            System.out.println("Animal");
        }
    }
    
    interface Common {
        void who();
    }
    
    Test.test(new Animal());
    

    汎用コードと仮想マシン
    タイプ消去
  • javaの汎用型はコンパイル段階に存在し、バイトコードにコンパイルすると汎用型がなく、仮想マシンには汎用型がない.
  • 汎用タイプはいずれも元のタイプに対応し、元のタイプはタイプパラメータを削除した後の汎用タイプ名であり、タイプ変数を消去し、限定タイプに置き換える(無限にObjectを用いる).
  • 限定タイプが複数ある場合、第1のタイプを選択して置き換える.

  • 汎用式の翻訳
    Pair pair ...
    String s = pair.getKey();
    -----------------------------
           
    String s = (String) pair.getKey();
    

    コンパイラは2つの命令に翻訳されます.
  • 元のメソッドの呼び出し.
  • が返すObjectは指定されたタイプに強く変わります.

  • 汎用メソッドの翻訳
    class Child extends Root {
        public void setNum(Integer a) {
            super.setNum(a);
        }
    }
    
    class Root {
        private T num;
        public void setNum(T num) {
            this.num = num;
        }
    }
    
    Child child = new Child();
    Root root = child; //  
    root.setNum(10);
    

    コンパイラは
     class Child extends Root {
         public void setNum(Integer a) {
             super.setNum(a);
         }
     }
     
     class Root {
         private Object num;
         public void setNum(Object num) {
             this.num = num;
         }
     }
    

    superは書き換え方法を呼び出しますが、書き換えは以下の要件を満たす必要があります.
  • パラメータリストは、書き換え方法と完全に同じ
  • でなければならない.
  • 戻りタイプは、書き換え方法の戻りタイプとは異なる場合がありますが、親の戻り値の派生クラスである必要があります(java 5以降の戻りタイプは同じで、java 7以降のバージョンは異なる場合があります).
  • アクセス権は、親クラスで書き換えられたメソッドのアクセス権よりも低くすることはできません.たとえば、親クラスのメソッドがpublicとして宣言されている場合、サブクラスでメソッドを書き換えるとprotectedとして宣言できません.
  • 親クラスのメンバーメソッドは、その子クラスによってのみ書き換えられます.
  • finalとして宣言されたメソッドは書き換えられません.
  • staticとして宣言されたメソッドは書き換えられないが、再宣言されることができる.
  • 子クラスと親クラスが同じパッケージにある場合、privateとfinalとして宣言されたメソッドを除いて、子クラスは親クラスのすべてのメソッドを書き換えることができます.
  • 子クラスと親クラスが同じパッケージにない場合、子クラスはpublicとprotectedと宣言された非finalメソッドのみを書き換えることができます.
  • 書き換えの方法は、書き換えられた方法が異常を投げ出すかどうかにかかわらず、任意の非強制異常を投げ出すことができる.しかし、書き換えの方法は、新しい強制的な異常を投げ出すことができず、あるいは書き換えの方法によって宣言されたよりも広範な強制的な異常を投げ出すことができず、逆に可能である.
  • の構成方法は書き換えられない.
  • メソッドを継承できない場合は、このメソッドを書き換えることはできません. 

  • 重荷をもうちょっと補充します
  • がリロードされる方法は、パラメータリスト(パラメータの個数またはタイプが異なる)を変更しなければならない.
  • がリロードされる方法は、戻りタイプを変更することができる.
  • がリロードされる方法は、アクセス修飾子を変更することができる.
  • が再ロードされた方法は、新しいまたはより広い検査異常を宣言することができる.
  • 方法は、同じクラスにおいて、または1つのサブクラスにおいて再ロードすることができる.
  • は、リロード関数の区分基準として戻り値タイプを使用できません.

  • 書き換えとリロードの違い
    区別する
    じゅうか
    書き換える
    パラメータリスト
    変更する必要があります
    変更できません
    戻りタイプ
    変更可能
    変更できません
    異常
    変更可能
    減らしたり削除したりすることができて、きっと新しいあるいはもっと広い異常を投げ出すことができません
    アクセス
    変更可能
    きっともっと厳しい制限はできない(制限を下げることができる)
    したがってsuperは親のpublic void setNum(Integer a)にアクセスできません したがって、コンパイラはサブクラスでブリッジメソッドを自動的に生成します.
    class Child extends Root {
         public void setNum(Integer a) {
             super.setNum(a);
         }
         public void setNum(Object a) {
             setNum((Integet)a);
         }
    /*
                    
    //ERROR
      public void setNum(Object a) {
             setNum((Integet)a);
         }
    */
     }
    

    Java汎用変換:
  • 仮想マシンには汎用性がなく、普通のクラスと方法しかありません.
  • すべてのタイプパラメータは、それらの限定タイプで置き換えられる.
  • ブリッジ法の合成は、多状態を維持するために用いられる.
  • はタイプの安全性を保証するため、必要に応じて強制タイプ変換を挿入する.

  • 制約と限界
    1.基本タイプでタイプパラメータをインスタンス化できません2.実行時タイプクエリーは元のタイプにのみ適用されます
    class Things { }
    
    class Animal { }
    
    class People { }
    
    Things things = new Things<>();
    Things peopleThings = new Things<>();
    System.out.println(""+things.getClass().getName());// Things
    System.out.println(""+peopleThings.getClass().getName());// Things
    boolean a = things instanceof Things; //              
    boolean b = things instanceof Things; //         true
    

    3.パラメトリックタイプの配列は作成できません.汎用配列は作成できません.
    Things[] things;//         new
    Things[] things = (Things[])new Things>[10];//            
    

    4.可変パラメータリストに汎用タイプのメソッドを追加する前に@SafeVarargsを追加する必要があります
    @SafeVarargs
    private static void add(List list, T... args) {
        list.addAll(Arrays.asList(args));
    }
    Things things1 = new Things<>();
    Things things2 = new Things<>();
    List> list = new ArrayList<>();
    add(list, things1, things2);
    

    5.タイプ変数をインスタンス化できない
    class Things {
        private T arg1 = new T();//      
    }
    

    正しく使用するには、関数インタフェースを使用するか、反射を使用する必要があります(tryを追加する必要があります):
    class Things {
        private T arg1;
        Things(T arg1) {
            this.arg1 = arg1;
        }
        public void getArg1() {
            System.out.println("type:"+arg1.getClass().getSimpleName()+" v"+arg1);
        }
    }
    
    /**
     * @param construct,               T    
     */
    private static  Things getObject(Supplier construct) {
        return new Things<>(construct.get());
    }
    
    /**
     *          Try Catch
     */
    private static  Things getObject(Class construct) {
        try {
            return new Things<>(construct.newInstance());
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    Things things = getObject(String:: new);
    //   
    Things things1 = getObject(String.class);
    things.getArg1();
    assert things1 != null;
    things1.getArg1();
    

    6.汎用クラスの静的コンテキストにおけるタイプ変数が無効である(静的属性は汎用を含まない)Singletonを考慮
    public class Singleton {
        private static T singlelnstance; // Error
        public static T getSinglelnstanceO // Error
        {
            if (singleinstance == null) construct new instance of T
                return singlelnstance;
        } 
     }
    

    7.汎用クラスのインスタンスを放出または取得できない
    catch句ではタイプ変数は使用できません
    汎用クラス拡張Throwableは合法的ではありません
    例外仕様でのタイプ変数の使用は許可されています
    //     
    public static  void doWork(Class t) {
        try
        {
            do work
        }
        catch (T e) // Error can 't catch type variable
        {
            Logger,global.info(...);
        }
    }
    //     
    public static  void doWork(T t) throws T {// OK
        try{
        do work;
        } catch (Throwable realCause){ 
            t.initCause(realCause);
            throw t;
        }
    }
    

    8.検査された異常に対する検査をなくすことができる
    すべての異常を指定された異常に包装して投げ出すことです
    class Block{
        @SuppressWarnings("unchecked")
        public static void throwAs(Throwable e) throws T {
            throw (T) e;
        }  
    }
    //          RuntimeException
    try {
        do work;
    }catch (Throwable t)
    {
        B1ock.throwAs(t) ;
    }

    ワイルドカードの種類
  • 形式:TypeClass extends Root〉
  • ワイルドカードのスーパータイプ限定TypeClass super Management> 
  • 無限ワイルドカードTypeClass>