Effective Java-オブジェクトの作成と破壊(1)


オブジェクトの作成と破壊


🎯 実行の目的

  • オブジェクトを作成するタイミングを決定する方法
  • 正しいオブジェクトを作成する方法と、不要な作成を避ける方法
  • が破壊され、破壊前に清掃作業が完了することを確認する
  • .

    📌 References.


    Effective Java

    🚀 Item1. ジェネレータではなく静的パラメータ法を考慮する


    クラスは、作成者とは独立して静的メソッドを提供できます.
    ここで、静的パラメータメソッドは、クラスインスタンスを返す簡単な静的メソッドです.
    EX)
    public static Boolean valueOf(boolean b){
        return b ? Boolean.TRUE : Boolean.FALSE;
    }
    この方法には長所もあれば短所もある.
    まず、その長所を見てみましょう.
    第一に、名前をつけることができます
    作成者にのみ渡されるパラメータと作成者自体は、返すオブジェクトのプロパティを正しく記述できない可能性があります.
    たとえば、BigIntegerのコンストラクション関数がある場合、小さな値が返されます.BigInteger(int, int, Random)よりもBigInteger.probablePrimeの方が意味があります.
    また、パラメータOverloadingを入力するだけで作成されるコンストラクタは、コンストラクタを追加すると、どのコンストラクタが何を意味するかを決定する
    難しいかもしれない
    したがって、クラスのインスタンスを作成するときに、名前付き静的パラメータメソッドを使用してインスタンスを作成できます.
    ただし、呼び出しのたびにインスタンスを再作成する必要はありません.
    静的パラメータメソッドは、インスタンスを事前に作成するか、新しく作成したインスタンスをキャッシュすることによって、これらのインスタンスを回収することができる.
    例えばStringのような不変クラス!
    String s=new String("Hello");
    String s=String.valueOf("Hello");
    new Stringは、もう1つのインスタンスを作成することを示す.したがって、同じ「Hello」でも、オブジェクトを追加作成するコストが必要になります.valueOfは、既存のオブジェクトをキャッシュすることによって提供される静的ファクトリ方法である.元の「ハロー」を提供します
    反復要求に同じオブジェクトを返す方法も싱글턴 패턴の基礎である.
    モノトーンの例
    public class Test1 {
        private int a;
        private int b;
        private static final Test1 test1=new Test1();
    
    // 기본 생성자
        public Test1() {
        }
    
        public Test1(int a, int b) {
            this.a=a;
            this.b=b;
        }
        
    
    //    singleton
        private Test1(){
        
        }
        public static Test1 getInstanceWithSingleton(){
            return test1;
        }
    
    }
    また、等値インスタンスが1つしかないことを確認できます.等値とは、互いに同じメモリ上に存在するオブジェクトを指します.
    第三に、戻りタイプを返すサブタイプオブジェクトを返す能力がある.
    この機能は、返すオブジェクトのクラスを自由に選択できる柔軟性を提供します.
    この柔軟性により、実装クラスを公開することなくオブジェクトを返すことができます.
    たとえば
    public interface Test2 {
        static Test2 getA(){
           return new A();
        }
    
        static Test2 getB(){
            return new B();
        }
        
    }
    
    class A implements Test2{
    
    }
    
    class B implements Test2{
    
    }
    これらのコードを使用できます.
    Java 8の前に、인터페이스で静的メソッドを宣言することはできません.したがって、静的メソッドがインタフェースに戻る必要がある場合、
    仲間レベルが入っているそうです
    public interface Test2 {
        class C implements Test2{
            private static final Test2 c=new C();
    
            private C(){
            }
    
            public static Test2 getInstance(){
                return c;
            }
        }    
    
    }
    第四に、入力パラメータに基づいて、異なるクラスのオブジェクトを毎回返すことができる
    要素の数に応じて、2つのサブクラスのインスタンスを返すことができます.EnumSetを例に挙げます.
    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
            Enum<?>[] universe = getUniverse(elementType);
            if (universe == null)
                throw new ClassCastException(elementType + " not an enum");
    
            if (universe.length <= 64)
                return new RegularEnumSet<>(elementType, universe);
            else
                return new JumboEnumSet<>(elementType, universe);
        }
    上記の静的方法で返されるパラメータ長は、それぞれ RegularEnumSetおよびJumboEnumSetである.
    今、欠点を理解してみましょう.
    第一に、共通または保護が必要な作成者を継承し、静的メソッドのみではサブクラスを作成できません.
    この点を理解するには、継承されたクラスがインスタンスを作成する方法を理解する必要があります.
    デフォルトでは、継承されたクラスはクラスを継承します.継承されたクラスを提供するメンバー変数、メンバーメソッドなどを使用するには、まず親クラスの
    インスタンス化が必要
    ただし、コンストラクション関数が存在せず、静的パラメータメソッドのみが提供されている場合は、サブクラスの作成時に親クラスを作成できないことを示します.
    したがって、子クラスが継承後に作成され、親クラスにコンストラクション関数がない場合はエラーが発生します.
    第二に、プログラマーは静的な方法を見つけるのが難しい.
    これは、APIの説明が作成者のように明確ではない可能性があるためです.ユーザーは静的メソッドクラスを
    これは、インスタンス化の方法を理解する必要があることを意味します.

    🚀 Item2. コンストラクション関数に多くのパラメータがある場合は、コンストラクタを考慮します。


    クラスを作成するとき、プログラマは점층적 생성자 패턴を使用します.
    必須パラメータのみを受け入れる作成者、必須パラメータを受け入れる作成者...これは、ジェネレータを増やし続ける方法を意味します.
    これらのポイント積層ジェネレータアレイのパラメータが多ければ多いほど、コンストレイントが多ければ多いほど、コードの作成や読み取りが難しくなります.
    これを補うために、Builderモードを使用します.
    どんなパターンなのか見てみましょう.
    1.ビルダーオブジェクトに背を向けるには、必要なパラメータのみを使用してビルダーを呼び出します.
    2.設定方法を使用して、必要な選択パラメータを設定します.
    3.最後に、パラメータなしのコンストラクションメソッドを呼び出してオブジェクトを作成して返します.
    コードを見てみましょう.
    public class Test1 {
        private int a;
        private int b;
        private int c;
    
        //Builder
        public static class Builder{
            //필수 매개변수
            private final int a;
    
            //선택 매개변수 - 기본값으로 초기화
            private int b=0;
            private int c=0;
    
            public Builder(int a){
                this.a=a;
            }
    
            public Builder b(int b){
                this.b=b;
                return this;
            }
    
            public Builder c(int c){
                this.c=c;
                return this;
            }
    
            public Test1 build(){
                return new Test1(this);
            }
        }
    
        private Test1(Builder builder){
            this.a= builder.a;
            this.b= builder.b;
            this.c= builder.c;
        }
        
        public static void Main(String[] args){
            Test1 build = new Builder(1).b(2).c(3).build();
        }
    }
    コンストラクタの設定方法はコンストラクタ自体を返すため、連続的に呼び出すことができます.
    コンストラクタモードは、階層設計のクラスとともに使用することもできます.
    抽象クラスでは、抽象コンストラクタを持つことができます.具体的なクラスでは、具体的なコンストラクタを持つことができます.
    Pizza,java
    public abstract class Pizza {
        public enum Topping{HAM, CHEESE}
        final Set<Topping> toppings;
    
        abstract static class Builder<T extends Builder<T>>{
            EnumSet<Topping> toppings=EnumSet.noneOf(Topping.class);
            public T addTopping(Topping topping){
                toppings.add(Objects.requireNonNull(topping));
                return self();
            }
    
            abstract Pizza build();
    
            protected abstract T self();
        }
    
        Pizza(Builder<?> builder){
            toppings=builder.toppings.clone();
        }
    }
    MyPizza.java
    public class MyPizza extends Pizza{
        public enum Size{SMALL,MEDIUM,LARGE}
        private final Size size;
    
        public static class Builder extends Pizza.Builder<Builder>{
            private final Size size;
    
            public Builder(Size size){
                this.size=size;
            }
    
            @Override
            public MyPizza build() {
                return new MyPizza(this);
            }
    
            @Override
            protected Builder self() {
                return this;
            }
        }
    
        private MyPizza(Builder builder){
            super(builder);
            this.size=builder.size;
        }
    }
    サブクラスのコンストラクタで定義されたコンストラクションメソッドは、特定のサブクラスを返します.
    これは、PizzaではなくMyPizzaを返すことを意味します.
    これらの機能を使用すると、クライアントは変換することなくコンストラクタを作成できます.
    欠点を理解しましょう.
    今まで勉強しました.
    コンストラクタモードは非常に柔軟です.パラメータを選択的に挿入したり、パラメータに基づいて他のオブジェクトを作成したりできます.
    欠点は、コンストラクタを生成するコストにつながる可能性があります.
    パフォーマンスに敏感な場合、コンストラクタの作成コストも問題になる可能性があります.
    したがって、ポイント積層ジェネレータアレイを完全に置き換えることができる(例えば、4つ以上のパラメータがある...)価値のある時、
    使用を推奨します.

    🚀 Item3. privateジェネレータまたは列挙タイプで単一ループであることを保証


    単一インスタンスとは、1つのインスタンスしか作成できないクラスです.
    public class Test1 {
        private int a;
        private int b;
        private static final Test1 test1=new Test1();
    
    // 기본 생성자
        public Test1() {
        }
    
        public Test1(int a, int b) {
            this.a=a;
            this.b=b;
        }
    
    //    singleton
        private Test1(){
            
        }
        public static Test1 getInstanceWithSingleton(){
            return test1;
        }
    
    }
    しかし、モノトーンの欠点も多い.
  • 専用ジェネレータを持っているため、継承できません.
  • をテストするのは難しいです.
  • 単色の製作方式は限られているため、試験で使用する際にネックオブジェクトなどで代用することは困難である.初期化の過程で、
    オブジェクトを動的に注入するのは難しい.
  • 単トンの使用は、グローバル状態を作成できるため、理想的ではありません.
  • serializableの実施を宣言するだけでは十分ではありません.
    単一ホイールにインスタンスが1つしかないことを確認する必要があります.これは、逆シリアル化時に新しいインスタンスを作成しないようにする必要があります.
    したがって、すべてのフィールドtransientを宣言し、readResolveメソッドを提供する必要があります.
    👍 それ以外に、Spring Binはこれらの問題を完全に解決して、それを単色調の状態を維持させます!
    さらに、Enumタイプを使用して単輪を作成することもできます.
    public enum Test1 {
        INSTANCE;
    }
    この方法はより簡潔で、シリアル化に追加の努力を必要としません.非常に複雑なシリアル化環境でも、インスタンスの出現を完全に回避できます.