「Effective Java」第1章-オブジェクトの作成と破棄

6328 ワード

内容は『Effective Java』(第2版、機械工業出版社)より抜粋
第一条:コンストラクタの代わりに静的工場法を考慮する
このようにするメリット
  • スタティックファクトリメソッドには名称があり、開発中にどのコンストラクタを使用すべきか忘れないように読みやすくすることができる
  • .
  • は呼び出しのたびに新しいオブジェクトを作成する必要がなく、可変クラス(インスタンスの内容が変更できないクラス)が必要な場合に予め構築されたインスタンスを使用することができ、オブジェクトの重複作成を回避し、パフォーマンスを向上させる
  • .
  • 元の戻りタイプの任意のサブタイプオブジェクトを返すことができ、柔軟性が向上する
  • パラメトリックタイプインスタンスを作成するとき、コードを簡潔にすることができる
  • .
    静的工場法の欠点
  • 類公有または保護されたコンストラクタを含まなければ、
  • を布団類化することはできない.
  • 他の静的方法とは実際には何の違いもありません.APIドキュメントのように
  • を直接明確に識別することはできません.
    静的メソッドの慣用名
  • valueOf-タイプ変換、そのパラメータと同じ値
  • を返します.
  • of-valueOfの簡潔な代替
  • getInstance--返されるインスタンスはメソッドのパラメータで記述されるが、パラメータと同じ値を持つとは言えない.Singleton(単一の例)では、変更方法にはパラメータがなく、一意のインスタンス
  • が返される.
  • newInstance-getInstanceと同様ですが、newInstanceは、返される各インスタンスが他の
  • と異なることを保証します.
  • getType--getInstanceのように、ファクトリメソッドが返すデータ型を表し、主に異なるクラスの場合に使用されます.
  • newType--newInstanceのようですが、工場メソッドが異なるクラスにある場合に使用します.Typeはファクトリメソッドが返すオブジェクトタイプ
  • を表す.
    サービスプロバイダフレームワーク
    複数のサービスプロバイダが1つのサービスを実現し、システムはサービスプロバイダのクライアントに複数の実装を提供し、それらを複数の実装からデカップリングする.これは静的ファクトリメソッドのインスタンスサービスプロバイダフレームワークの4つの部分を含む
  • サービスインタフェース(Service Interface)は、プロバイダが実装する
  • である.
  • プロバイダはAPI(Provider Registation API)を登録し、これはシステムが実装を登録し、クライアントにアクセスさせるために使用される.
  • サービスアクセスAPI(Service Access API)は、クライアントがサービスを取得するために使用するインスタンスである.一般に、クライアントがプロバイダを選択する条件を指定する必要はありませんが、クライアントがこのような指定をしていない場合、デフォルトのインスタンスに返されます.「柔軟な静的工場」であり、サービスプロバイダのフレームワークの基礎
  • を構成しています.
  • サービスプロバイダインタフェース(Service Provider Interface)は、サービス実装のインスタンスを作成するオプションです.インスタンスが指定されていない場合、インプリメンテーションはクラス名で登録され、反射的にインスタンス化されます.

  • 第二条:複数のコンストラクタパラメータに遭遇した場合、コンストラクタを使用することを考慮する
    1つのエンティティに複数のプロパティがあり、必要でないプロパティがある場合は、インスタンスを作成するときに複数のコンストラクション関数を選択できます.たとえば、次のようになります.
    package com.myclass;
    
    public class OldPerson {
        private int age;
        private String name;
        private double weight;
        private String hobby;
        public OldPerson(int age, String name, double weight, String hobby) {
            // TODO Auto-generated constructor stub
            this.age = age;
            this.name = name;
            this.weight = weight;
            this.hobby = hobby;
        }
        
        // weight hobby       ,     OldPerson     
        public OldPerson(int age, String name) {
            this.age = age;
            this.name = name;
        }
    }
    

    複数のパラメータがある場合、コンストラクタは多く、使用中に2つのパラメータまたは他の小さな問題を誤って逆転させる可能性があるため、このようなオーバーラップコンストラクタモードは可能であるが、多くのパラメータがある場合、クライアントコードは書きにくく、読みにくい.
    より良い方法
    package com.myclass;
    
    public class Person {
        private int age;
        private String name;
        private double weight;
        private String hobby;
        
        public static class Builder {
            //    
            private String name;
            
            //    ,     
            private int age = 0;
            private double weight = 0.0;
            private String hobby = " bug";
            
            //      
            public Builder (String name) {
                this.name = name;
            }
            
            //       
            public Builder age(int age) {
                this.age = age;
                return this;
            }
            public Builder weight(int weight) {
                this.weight = weight;
                return this;
            }
            public Builder hobby(String hobby) {
                this.hobby = hobby;
                return this;
            }
            
            public Person build() {
                return new Person(this);
            }
        }
        
        public Person(Builder builder) {
            // TODO Auto-generated constructor stub
            age = builder.age;
            name = builder.name;
            weight = builder.weight;
            hobby = builder.hobby;
        }
    }
    
    

    このように私たちが使用するときはこのようにする必要があります.
         Person person = new Person.Builder("Slience   ").weight(120).hobby("  ").build();
    
    

    それでいいです(JavaBeanモードを使うことが多いですが)
    第三条:プライベートコンストラクタまたは列挙タイプでSingleton属性を強化する
    (これはあまり読めませんでした)
    第四条:私有コンストラクタによるインスタンス化不可能な能力の強化
    クラスに明示的なコンストラクタがない場合、デフォルトのコンストラクタが自動的に生成されることを知っています.クラスをインスタンス化できないようにしたい場合(ツールクラスなど)、自分でコンストラクタを書き、コンストラクタをプライベートに設定することで、このインスタンスは作成されません.例えば、
    package com.myclass;
    
    public class MyClass {
        public static String say() {
            return "Hello World";
        }
        private MyClass() {
            // TODO Auto-generated constructor stub
        }
    }
    
    

    これでMyClassインスタンスは作成できませんが、sayメソッドしか使用できません.
    第五条:不要なオブジェクトの作成を避ける
    String str = "Hello World";
    String str2 = new String("Hello World");
    

    strはstr 2に比べて効率的です.オブジェクトを作成するときに「Hello World」はすでにオブジェクトであるため、new Stringでラップしてオブジェクトを作成する必要はありません.もう一つ例を挙げる
            long start = System.currentTimeMillis();
            long sum = 0L;
            for(long i = 0; i < Integer.MAX_VALUE; i++) {
                sum += i;
            }
            System.out.println(sum);
            System.out.println("  :" + (System.currentTimeMillis() - start));
    

    および
            long start = System.currentTimeMillis();
            Long sum = 0L;
            for(long i = 0; i < Integer.MAX_VALUE; i++) {
                sum += i;
            }
            System.out.println(sum);
            System.out.println("  :" + (System.currentTimeMillis() - start));
    

    両者の実行時間は異なり、後者はLongを使用する時間がより大きい.iをLongに変換してsumに加えるため、プログラムが不要な多くのLongインスタンスを創造し、より多くの時間を費やしたことを意味する.
    第六条:期限切れのオブジェクト参照を削除する
    (原書はスタックの増加がさらに減少した例である)減少した要素はごみに回収されず、極端な場合はメモリの漏れを引き起こす可能性がある.これは、スタック内部のメンテナなどのオブジェクトの期限切れのアプリケーションのためです.期限切れアプリケーションとは、いつまでも解除されない参照です.この問題を解決する方法も簡単です.それは、オブジェクトの参照が期限切れになったときに、これらの参照を空にすればいいということです.
            String[] strs = {"   ","   ","   ","   "};
            //         ,    
            String str = strs[strs.length-1];
            strs[strs.length-1] = null;
            System.out.println(str);
    

    このような利点は、誤った参照を解除すると、プログラムがひっそりと実行するのではなく、空のポインタの異常を報告することです.
    第七条:終結方法の使用を避ける
    エンドメソッドfinalizerのスレッド優先度は他のアプリケーションのスレッドよりも低く、finalizerを使用して限られたリソースを終了する場合は、例えば多くのファイルを開く記述子(原文ではexplorerのようなものかもしれません)を使用して、それをオフにしたいときに新しいものを開きます.優先度が低いため、新しいものを先に開けて古いものを消していない可能性があります.閉じる速度が開く速度より低いため、リソースの占有量が発生します.一般的な終結方法としては、InputStream、java.sql.connentionのcolseメソッドがあります.終了メソッドを表示するには、通常try-finallyと組み合わせて使用され、タイムリーな終了を確保します.終了メソッドの前にtry-finallyを使用して終了のメリットを表示
  • は、終了方法の「セキュリティネットワーク」として機能し、終了方法が時間通りに閉じられなくても、いくつかの救済のために動作することができる.