• 设计模式课程 设计模式精讲 8-8 单例设计模式-Enum枚举单例、原理源码解析以及反编译实战


    1    课堂解析

    2    代码演练

    2.1  枚举类单例解决序列化破坏demo

    2.2  枚举类单例解决序列化破坏原理

    2.3  枚举类单例解决反射攻击demo

    2.4  枚举类单例解决反射攻击原理

    3    jad的使用

    3.1  网址:

    1    课堂解析
    2    代码演练
    2.1  枚举类单例解决序列化破坏demo

    枚举类:

    package com.geely.design.pattern.creational.singleton;
    
    /**
     * 这个类是enum类型
     */
    public enum  EnumInstance {
        INSTANCE;
        private Object data;
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
    /**
         * Java类中的静态变量在程序运行期间,其内存空间对所有该类的对象实例而言是共享的,有些时候可以认为是全局变量。
         * 因此在某些时候为了节省系统内存开销、共享资源,可以将类中的一些变量声明为静态变量!
         *
         * 最最主要的原因,单例模式外部类不能new出对象,要使用该方法只能是静态的
         *
         * 最终返回的肯定是本类,所以该方法的类型为EnumInstance
         */
        public static EnumInstance getInstane(){
            return INSTANCE;
        }
    
    }

    测试类:

    package com.geely.design.pattern.creational.singleton;
    
    import java.io.*;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class Test {
        /**
         * 序列化代码演练
         * 将 HungrySingleton对象放入文件,再从文件读取该对象,还是同一个对象吗?
         * 实际应用:在从文件存入后读取,用equals时需要注意(equals比较的是hash码)
         *
         * @param args
         */
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            try {
                //将singleton对象写入到输出流中
                EnumInstance instance = EnumInstance.getInstane();
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
                oos.writeObject(instance);
    
                //从输入流中读取到该对象
                File file = new File("singleton_file");
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
                EnumInstance instance2 = (EnumInstance) ois.readObject();
                System.out.println(instance);
                System.out.println(instance2);
                System.out.println(instance == instance2);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
    
        }
    }

    打印日志:

    "C:Program FilesJavajdk1.7.0_79injava.exe" "-javaagent:D:javadevolopKitideaanZhIntelliJ IDEA Community Edition 2018.1.4libidea_rt.jar=42967:D:javadevolopKitideaanZhIntelliJ IDEA Community Edition 2018.1.4in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.7.0_79jrelibcharsets.jar;C:Program FilesJavajdk1.7.0_79jrelibdeploy.jar;C:Program FilesJavajdk1.7.0_79jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.7.0_79jrelibextdnsns.jar;C:Program FilesJavajdk1.7.0_79jrelibextjaccess.jar;C:Program FilesJavajdk1.7.0_79jrelibextlocaledata.jar;C:Program FilesJavajdk1.7.0_79jrelibextsunec.jar;C:Program FilesJavajdk1.7.0_79jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.7.0_79jrelibextsunmscapi.jar;C:Program FilesJavajdk1.7.0_79jrelibextzipfs.jar;C:Program FilesJavajdk1.7.0_79jrelibjavaws.jar;C:Program FilesJavajdk1.7.0_79jrelibjce.jar;C:Program FilesJavajdk1.7.0_79jrelibjfr.jar;C:Program FilesJavajdk1.7.0_79jrelibjfxrt.jar;C:Program FilesJavajdk1.7.0_79jrelibjsse.jar;C:Program FilesJavajdk1.7.0_79jrelibmanagement-agent.jar;C:Program FilesJavajdk1.7.0_79jrelibplugin.jar;C:Program FilesJavajdk1.7.0_79jrelib
    esources.jar;C:Program FilesJavajdk1.7.0_79jrelib
    t.jar;F:xiangmu3XinIdeadesign_pattern	argetclasses" com.geely.design.pattern.creational.singleton.Test
    INSTANCE
    INSTANCE
    true
    
    Process finished with exit code 0
    2.2  枚举类单例解决序列化破坏原理

    ObjectInputStream

    /**
         * Underlying readObject implementation.
         */
        private Object readObject0(boolean unshared) throws IOException {
            boolean oldMode = bin.getBlockDataMode();
            if (oldMode) {
                int remain = bin.currentBlockRemaining();
                if (remain > 0) {
                    throw new OptionalDataException(remain);
                } else if (defaultDataEnd) {
                    /*
                     * Fix for 4360508: stream is currently at the end of a field
                     * value block written via default serialization; since there
                     * is no terminating TC_ENDBLOCKDATA tag, simulate
                     * end-of-custom-data behavior explicitly.
                     */
                    throw new OptionalDataException(true);
                }
                bin.setBlockDataMode(false);
            }
    
            byte tc;
            while ((tc = bin.peekByte()) == TC_RESET) {
                bin.readByte();
                handleReset();
            }
    
            depth++;
            try {
                switch (tc) {
                    case TC_NULL:
                        return readNull();
    
                    case TC_REFERENCE:
                        return readHandle(unshared);
    
                    case TC_CLASS:
                        return readClass(unshared);
    
                    case TC_CLASSDESC:
                    case TC_PROXYCLASSDESC:
                        return readClassDesc(unshared);
    
                    case TC_STRING:
                    case TC_LONGSTRING:
                        return checkResolve(readString(unshared));
    
                    case TC_ARRAY:
                        return checkResolve(readArray(unshared));
               /*
                     * 注意:读取enum
                     *
                     */
    case TC_ENUM: return checkResolve(readEnum(unshared)); case TC_OBJECT: return checkResolve(readOrdinaryObject(unshared)); case TC_EXCEPTION: IOException ex = readFatalException(); throw new WriteAbortedException("writing aborted", ex); case TC_BLOCKDATA: case TC_BLOCKDATALONG: if (oldMode) { bin.setBlockDataMode(true); bin.peek(); // force header read throw new OptionalDataException( bin.currentBlockRemaining()); } else { throw new StreamCorruptedException( "unexpected block data"); } case TC_ENDBLOCKDATA: if (oldMode) { throw new OptionalDataException(true); } else { throw new StreamCorruptedException( "unexpected end of block data"); } default: throw new StreamCorruptedException( String.format("invalid type code: %02X", tc)); } } finally { depth--; bin.setBlockDataMode(oldMode); } } /** * Reads in and returns enum constant, or null if enum type is * unresolvable. Sets passHandle to enum constant's assigned handle. */ private Enum readEnum(boolean unshared) throws IOException { if (bin.readByte() != TC_ENUM) { throw new InternalError(); } ObjectStreamClass desc = readClassDesc(false); if (!desc.isEnum()) { throw new InvalidClassException("non-enum class: " + desc); } int enumHandle = handles.assign(unshared ? unsharedMarker : null); ClassNotFoundException resolveEx = desc.getResolveException(); if (resolveEx != null) { handles.markException(enumHandle, resolveEx); } String name = readString(false);//通过readString方法获取到枚举对象的名称 Enum en = null; Class cl = desc.forClass(); if (cl != null) { try { en = Enum.valueOf(cl, name);//通过类型和名称获取到枚举常量,枚举中的name是唯一的,并且对应一个枚举常量,所以拿到的肯定是唯一的对象。 } catch (IllegalArgumentException ex) { throw (IOException) new InvalidObjectException( "enum constant " + name + " does not exist in " + cl).initCause(ex); } if (!unshared) { handles.setObject(enumHandle, en); } } handles.finish(enumHandle); passHandle = enumHandle; return en; }
    2.3  枚举类单例解决反射攻击demo

    枚举类:(同2.1)

    package com.geely.design.pattern.creational.singleton;
    
    /**
     * 这个类是enum类型
     */
    public enum  EnumInstance {
        INSTANCE;
        private Object data;
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
    /**
         * Java类中的静态变量在程序运行期间,其内存空间对所有该类的对象实例而言是共享的,有些时候可以认为是全局变量。
         * 因此在某些时候为了节省系统内存开销、共享资源,可以将类中的一些变量声明为静态变量!
         *
         * 最最主要的原因,单例模式外部类不能new出对象,要使用该方法只能是静态的
         *
         * 最终返回的肯定是本类,所以该方法的类型为EnumInstance
         */
        public static EnumInstance getInstane(){
            return INSTANCE;
        }
    
    }

    测试类:

    package com.geely.design.pattern.creational.singleton;
    
    import java.io.*;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class Test {
    
        /**
         * 序列化代码演练
         * 将 HungrySingleton对象放入文件,再从文件读取该对象,还是同一个对象吗?
         * 实际应用:在从文件存入后读取,用equals时需要注意(equals比较的是hash码)
         *
         * @param args
         */
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            /*try {
                //将singleton对象写入到输出流中
                EnumInstance instance = EnumInstance.getInstane();
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
                oos.writeObject(instance);
    
                //从输入流中读取到该对象
                File file = new File("singleton_file");
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
                EnumInstance instance2 = (EnumInstance) ois.readObject();
                System.out.println(instance);
                System.out.println(instance2);
                System.out.println(instance == instance2);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }*/
    
            Class objectClass = EnumInstance.class;
            Constructor constructor = objectClass.getDeclaredConstructor();
            constructor.setAccessible(true);
    
    
        }
    }

    打印结果:

    "C:Program FilesJavajdk1.7.0_79injava.exe" "-javaagent:D:javadevolopKitideaanZhIntelliJ IDEA Community Edition 2018.1.4libidea_rt.jar=43086:D:javadevolopKitideaanZhIntelliJ IDEA Community Edition 2018.1.4in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.7.0_79jrelibcharsets.jar;C:Program FilesJavajdk1.7.0_79jrelibdeploy.jar;C:Program FilesJavajdk1.7.0_79jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.7.0_79jrelibextdnsns.jar;C:Program FilesJavajdk1.7.0_79jrelibextjaccess.jar;C:Program FilesJavajdk1.7.0_79jrelibextlocaledata.jar;C:Program FilesJavajdk1.7.0_79jrelibextsunec.jar;C:Program FilesJavajdk1.7.0_79jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.7.0_79jrelibextsunmscapi.jar;C:Program FilesJavajdk1.7.0_79jrelibextzipfs.jar;C:Program FilesJavajdk1.7.0_79jrelibjavaws.jar;C:Program FilesJavajdk1.7.0_79jrelibjce.jar;C:Program FilesJavajdk1.7.0_79jrelibjfr.jar;C:Program FilesJavajdk1.7.0_79jrelibjfxrt.jar;C:Program FilesJavajdk1.7.0_79jrelibjsse.jar;C:Program FilesJavajdk1.7.0_79jrelibmanagement-agent.jar;C:Program FilesJavajdk1.7.0_79jrelibplugin.jar;C:Program FilesJavajdk1.7.0_79jrelib
    esources.jar;C:Program FilesJavajdk1.7.0_79jrelib
    t.jar;F:xiangmu3XinIdeadesign_pattern	argetclasses" com.geely.design.pattern.creational.singleton.Test
    Exception in thread "main" java.lang.NoSuchMethodException: com.geely.design.pattern.creational.singleton.EnumInstance.<init>()
        at java.lang.Class.getConstructor0(Class.java:2892)
        at java.lang.Class.getDeclaredConstructor(Class.java:2058)
        at com.geely.design.pattern.creational.singleton.Test.main(Test.java:148)
    
    Process finished with exit code 1

    反射有参对象:

    package com.geely.design.pattern.creational.singleton;
    
    import java.io.*;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class Test {
        /**
         * 序列化代码演练
         * 将 HungrySingleton对象放入文件,再从文件读取该对象,还是同一个对象吗?
         * 实际应用:在从文件存入后读取,用equals时需要注意(equals比较的是hash码)
         *
         * @param args
         */
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            /*try {
                //将singleton对象写入到输出流中
                EnumInstance instance = EnumInstance.getInstane();
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
                oos.writeObject(instance);
    
                //从输入流中读取到该对象
                File file = new File("singleton_file");
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
                EnumInstance instance2 = (EnumInstance) ois.readObject();
                System.out.println(instance);
                System.out.println(instance2);
                System.out.println(instance == instance2);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }*/
    
            Class objectClass = EnumInstance.class;
            Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
            constructor.setAccessible(true);
            EnumInstance enumInstance = (EnumInstance) constructor.newInstance("dd",123);
    
    
        }
    }

    打印结果:

    Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
        at java.lang.reflect.Constructor.newInstance(Constructor.java:521)
        at com.geely.design.pattern.creational.singleton.Test.main(Test.java:150)
    
    Process finished with exit code 1
    2.4  枚举类单例解决反射攻击原理

    Enum.java

    只有有参构造器

        protected Enum(String name, int ordinal) {
            this.name = name;
            this.ordinal = ordinal;
        }

    Constructor.java 

      /**
         * Uses the constructor represented by this {@code Constructor} object to
         * create and initialize a new instance of the constructor's
         * declaring class, with the specified initialization parameters.
         * Individual parameters are automatically unwrapped to match
         * primitive formal parameters, and both primitive and reference
         * parameters are subject to method invocation conversions as necessary.
         *
         * <p>If the number of formal parameters required by the underlying constructor
         * is 0, the supplied {@code initargs} array may be of length 0 or null.
         *
         * <p>If the constructor's declaring class is an inner class in a
         * non-static context, the first argument to the constructor needs
         * to be the enclosing instance; see section 15.9.3 of
         * <cite>The Java&trade; Language Specification</cite>.
         *
         * <p>If the required access and argument checks succeed and the
         * instantiation will proceed, the constructor's declaring class
         * is initialized if it has not already been initialized.
         *
         * <p>If the constructor completes normally, returns the newly
         * created and initialized instance.
         *
         * @param initargs array of objects to be passed as arguments to
         * the constructor call; values of primitive types are wrapped in
         * a wrapper object of the appropriate type (e.g. a {@code float}
         * in a {@link java.lang.Float Float})
         *
         * @return a new object created by calling the constructor
         * this object represents
         *
         * @exception IllegalAccessException    if this {@code Constructor} object
         *              is enforcing Java language access control and the underlying
         *              constructor is inaccessible.
         * @exception IllegalArgumentException  if the number of actual
         *              and formal parameters differ; if an unwrapping
         *              conversion for primitive arguments fails; or if,
         *              after possible unwrapping, a parameter value
         *              cannot be converted to the corresponding formal
         *              parameter type by a method invocation conversion; if
         *              this constructor pertains to an enum type.
         * @exception InstantiationException    if the class that declares the
         *              underlying constructor represents an abstract class.
         * @exception InvocationTargetException if the underlying constructor
         *              throws an exception.
         * @exception ExceptionInInitializerError if the initialization provoked
         *              by this method fails.
         */
        @CallerSensitive
        public T newInstance(Object ... initargs)
            throws InstantiationException, IllegalAccessException,
                   IllegalArgumentException, InvocationTargetException
        {
            if (!override) {
                if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                    Class<?> caller = Reflection.getCallerClass();
                    checkAccess(caller, clazz, null, modifiers);
                }
            }
            if ((clazz.getModifiers() & Modifier.ENUM) != 0)//如果目标类是枚举类型,抛出异常
                throw new IllegalArgumentException("Cannot reflectively create enum objects");
            ConstructorAccessor ca = constructorAccessor;   // read volatile
            if (ca == null) {
                ca = acquireConstructorAccessor();
            }
            return (T) ca.newInstance(initargs);
        
    3    jad的使用
     3.1  网址:

    https://varaneckas.com/jad/

  • 相关阅读:
    window.fonts
    smpt authentification 配置
    如何从思维上应对
    中文字体 英文字体
    Path Breadcrumbs
    drupal commerce app
    做视频或者什么模块开发之类的
    分页符 箭头 难看
    theme wrapper 例子
    background position 稍微深入
  • 原文地址:https://www.cnblogs.com/1446358788-qq/p/11392203.html
Copyright © 2020-2023  润新知