effecitve java 3 singleton 1

5258 ワード

  • は、単一の例を保証するために、コンストラクタをプライベート化し、クライアントアクセスのために静的変数または静的メソッドを提供する必要がある.
  • 静的変数を使用して単一の例を実装します.この静的変数はfinalで修飾され、他の新しく作成されたオブジェクトを指ささないことを保証します.彼は静的であるべきです.このクラスはこのオブジェクトしかないので、クラスを通じてそれを見つける以外にこのオブジェクトにアクセスできる手段はありません.インターリーブの知識点は,クライアントが反射によって構造方法を実行することによってオブジェクトを得ることを防御するためには,構造方法に判断を加える,異常
    package singleton.finalfield;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    class Elvis{
        public static final Elvis INSTANCE =  new Elvis();
        private Elvis(){
            //           ,             
            if (null != INSTANCE) {
                throw  new RuntimeException("Elvis is singleton class, you can not create another one !!!!!!!!!!");
            }
        }
        public void saySth(){
            System.out.println("something");
        }
    }
    
    
    public class FinalFieldTest {
        public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
            Class elvisClass = Elvis.class;
            Constructor>[] constructors = elvisClass.getDeclaredConstructors();
            for (Constructor> constructor : constructors) {
                constructor.setAccessible(true);
            }
            Elvis elvis = (Elvis) constructors[0].newInstance();
        }
    }
    
  • を投げ出すことができる.
  • 静的ファクトリメソッドを使用して、単一のメンバー変数修飾子をprivateに設定し、1つの静的ファクトリメソッドでこのオブジェクトを外部に露出することに3つのメリットがあります.
  • はAPI上でこれが単一のクラス
  • であることを明確に見ることができる.
  • は、必要に応じて、1つのスレッドが1つのオブジェクト
  • しか持たない場合の「単一の例」を行うことができる.
  • は、方法呼び出し、すなわちElvis::instanceのような呼び出し方式
    package singleton.staticfactorymethod;
    
    class Elvis{
        private static final Elvis INSTANCE = new Elvis();
        private Elvis(){}
        public static Elvis getInstance(){
            return INSTANCE;
        }
    }
    
    
    public class StaticFactoryMethodTest {
        public static void main(String[] args) {
            Elvis instance = Elvis.getInstance();
        }
    }
    
  • をサポートすることができる.
  • 特に指摘する必要があるのは、シーケンス化に関する技術を使用する場合、単例の保証には特に注意が必要である.上の2つのコードは、Evelisがシーケンス化のインタフェースを実現し、オブジェクトをシーケンス化した後、複数回の逆シーケンス化を行った後、複数のオブジェクトが得られ、単例も破壊され、シーケンス化と同時に単例が保証される場合、シーケンス化インタフェースを実装後、resolveメソッドを書き換えて、単例
    package singleton.antiserialization;
    
    import java.io.*;
    
    class Elvis implements Serializable {
        public static final  Elvis INSTANCE =  new  Elvis();
        private Elvis(){
            if (null != INSTANCE) {
                throw  new RuntimeException("Elvis is singleton class, you can not create another one !!!!!!!!!!");
            }
        }
        public void saySth(){
            System.out.println("something");
        }
        //   readResolve  ,       ,                     
        private Object readResolve(){
            return INSTANCE;
        }
    }
    
    public class AntiSerializationTest {
    
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("Object.txt"));
            Elvis elvis = (Elvis) objectInputStream.readObject();
            ObjectInputStream objectInputStream2 = new ObjectInputStream(new FileInputStream("Object.txt"));
            Elvis elvis2 = (Elvis) objectInputStream2.readObject();
            System.out.println(elvis == elvis2);
        }
    
        public static void write(String[] args) throws IOException {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("object.txt"));
            Elvis instance = Elvis.INSTANCE;
            objectOutputStream.writeObject(instance);
            objectOutputStream.close();
        }
    }
    
  • を保証することができる.
  • 以上の点についてjavaが提供するenumを使用して様々な問題を解決することができ、反射を使用してオブジェクトの作成を行うことを防止することができ、逆シーケンスのリスクもありません.以下はテストコードで、自分で走って
    package singleton.enummethod;
    
    import java.io.*;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    enum Elvis{
        ONE;
        public void saySth(){
            System.out.println("hello");
        }
    }
    
    public class EnumTest {
    
        public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
            Class elvisClass = Elvis.class;
            Constructor>[] declaredConstructors = elvisClass.getDeclaredConstructors();
            for (Constructor> declaredConstructor : declaredConstructors) {
                declaredConstructor.setAccessible(true);
            }
            Object o = declaredConstructors[0].newInstance();
        }
    
        public static void read(String[] args) throws IOException, ClassNotFoundException {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("Object2.txt"));
            Elvis elvis = ( Elvis) objectInputStream.readObject();
            ObjectInputStream objectInputStream2 = new ObjectInputStream(new FileInputStream("Object2.txt"));
            Elvis elvis2 = (Elvis) objectInputStream2.readObject();
            System.out.println(elvis == elvis2);
        }
    
        public static void write(String[] args) throws IOException {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("object2.txt"));
            objectOutputStream.writeObject(Elvis.ONE);
            objectOutputStream.close();
        }
    
    }
    
  • を見ることができます.