单例模式防反射及性能(二)

单例模式的目的是创建一个对象,但是反射的方式,或者使用反序列的方式,就会对这种目的造成威胁,那么我们先来看看如何使用反射,如何使用反序列化,创建构造函数私有化的对象,以及我们如何防止反序列化创建对象。

1.补充:如何选用单例模式

 (1)占用资源少,不需要延迟加载的,一般使用的是枚举和饿汉式,但是枚举比饿汉式安全。

 (2)占用资源大,需要延迟加载,一般使用静态内部类和懒汉式,静态内部类好于懒汉式,因为他更加的懒汉式、线程安全、调用的效率高。

2.使用反射破解的时候,一般是不包括枚举的,所以他的安全性是恒爱的。

3.方式一:反射破解

package kw.test.sjms;

import java.io.Serializable;

/*
 * 懒汉式防止破解,原始单例程序
 */
public class FDemoLH implements Serializable{
    private static FDemoLH instance ;

    private FDemoLH()
    {}

    public synchronized static FDemoLH  getinstance(){
        if(instance == null)
        {
            instance = new FDemoLH();
        }
        return instance;
    }
}

破解程序

package kw.test.sjms;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;

public class FClient {
    public static void main(String[] args) throws Exception {
      /*
       * 反射的方法调用私有的构造函数。
       */
        FDemoLH fDemoLH1 = FDemoLH.getinstance();
        FDemoLH fDemoLH2 = FDemoLH.getinstance();
        System.out.println(fDemoLH1 == fDemoLH2);

        String className = "kw.test.sjms.FClient";
        Class<FDemoLH> clazz = (Class<FDemoLH>)Class.forName("kw.test.sjms.FDemoLH");
        Constructor<FDemoLH> c= clazz.getDeclaredConstructor(null);
        c.setAccessible(true); //跳过检查
        FDemoLH fd1 = c.newInstance();
        FDemoLH fd2 = c.newInstance();

        System.out.println(fd1);
        System.out.println(fd2);

    }
}

方式二:反序列化破解

package kw.test.sjms;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;

public class FClient {
    public static void main(String[] args) throws Exception {
        /*
         * 序列化
         */
        FDemoLH fDemoLH1 = FDemoLH.getinstance();
        System.out.println(fDemoLH1);
        FileOutputStream fileOutputStream = new FileOutputStream("D:/a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fileOutputStream);
        oos.writeObject(fDemoLH1);
        oos.close();
        fileOutputStream.close();
        /*
         * 反序列化
         */
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/a.txt"));
        FDemoLH fDemoLH = (FDemoLH)ois.readObject();
        System.out.println(fDemoLH);
    }
}

其他的单例方式类似

4.防止破解的方式

package kw.test.sjms;

import java.io.Serializable;

/*
 * 懒汉式防止破解
 */
public class FDemoLH implements Serializable{
    private static FDemoLH instance ;

    private FDemoLH()
    {}

    public synchronized static FDemoLH  getinstance(){
        if(instance == null)
        {
            instance = new FDemoLH();
        }
        return instance;
    }

    /*
     * 此方法是私有的,我尝试过公有,好像是不起作用的
     * */
    private Object readResolve()
    {
        return instance;
    }
}

5.下来测试效率,模拟多线程,打印出每种方式占用的时间。或者使用CountDownLatch类,他是一个多线程的辅助类,观察其他线程有没有执行完。它的内部有一个计算器,当一个线程执行完了就会将计数器减一。Wait方法等待其他线程执行完。

最终的结果是饿汉式最快、枚举、静态内部类、双重检测式、懒汉式依次变慢。

原文地址:https://www.cnblogs.com/kw28188151/p/8548338.html

时间: 2024-08-28 06:28:08

单例模式防反射及性能(二)的相关文章

[C#.NET] C#中使用反射的性能分析

最近在研究一个可配置系统的框架,在代码中大量使用了反射的方法,虽然借鉴到其他的语言,如java中反射性能都比较差,但是想到c#既然是一种强类型的语言,对于AppDomain中的类的调用应该性能不会差很多.   今天在mvp站点上看到有人说反射的性能很差,要避免使用,就写了一个简单的例子测试了一下   测试类如下:   namespace ReflectionTest.Test   {    public class CTester    {    public CTester()    {   

用Netty和Raphael来写塔防online游戏(二) - JS中使用protobuf协议

一. 简单介绍一下protobuf: Protocol Buffers are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more, originally designed at Google . 如今,已经有人用JS实现了protobuf协议,就是ProtoBu

再看ExpressionTree,Emit,反射创建对象性能对比

[前言] 前几日心血来潮想研究着做一个Spring框架,自然地就涉及到了Ioc容器对象创建的问题,研究怎么高性能地创建一个对象.第一联想到了Emit,兴致冲冲写了个Emit创建对象的工厂.在做性能测试的时候,发现居然比反射Activator.CreateInstance方法创建对象毫无优势可言.继而又写了个Expression Tree的对象工厂,发现和Emit不相上下,比起系统反射方法仍然无优势可言. 第一时间查看了园内大神们的研究,例如: Leven 的 探究.net对象的创建,质疑<再谈A

golang 反射应用(二)

golang反射应用(二) package test import ( "reflect" "testing" ) //定义适配器 func TestReflect(t *testing.T){ //声明回调函数 call1 := func(v1,v2 int){ t.Log(v1,v2) //1 2 } call2 := func(v1,v2 int,s string){ t.Log(v1,v2,s) //1 2 test2 } //定义全局变量 var ( fu

Java 反射理解(二)-- 动态加载类

Java 反射理解(二)-- 动态加载类 概念 在获得类类型中,有一种方法是 Class.forName("类的全称"),有以下要点: 不仅表示了类的类类型,还代表了动态加载类 编译时刻加载类是静态加载类,运行时刻加载类是动态加载类 演示 我们以具体的代码来演示什么是动态加载类和静态加载类: 新建:Office.java: class Office { public static void main(String[] args) { // new 创建对象,是静态加载类,在编译时刻就需

java反射机制性能优化

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; public class DynamicServer { private static Logger log = Logger.getLogger(DynamicServ

第三节:反射的性能

反射是相当强大的一个机制,它允许在运行时发现并使用编译时还不了解的类型及其成员.但是,它也有下面两个缺点: 1 .反射会造成编译时无法保证类型的安全性,由于反射要严重依赖于字符串,所以会丧失编译时类型安全.例如:假如执行Type.GetType(“Jef”);要求通过反射在一个程序中查找一个名为”Jef”的类型,但程序集包含的实际是”Jeff”类型,代码会通过编译,但是在运行时会出错,因为作为实参传递的类型名称被错误地拼写. 2.反射速度慢.使用反射时,类型以及成员的名称在编译时未知:要使用字符

java反射学习之二万能EXCEL导出

一.EXCEL导出的实现过程 假设有一个对象的集合,现在需要将此集合内的所有对象导出到EXCEL中,对象有N个属性:那么我们实现的方式是这样的: 循环这个集合,在循环集合中某个对象的所有属性,将这个对象的所有属性作为EXCEL的列,该对象占据EXCEL的一行 二.万能EXCEL导出(以JXL为例,jxl.poi等excel导入导出的jar包不做介绍了) 1.创建java工程.引入jxl的jar包 2.直接上代码 Book.java /** * Book对象 * @author bwy * */

反射机制,反射的性能,如何优化?

反射机制的定义: 是在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制. 反射的作用: 1.动态地创建类的实例,将类绑定到现有的对象中,或从现有的对象中获取类型. 2.应用程序需要在运行时从某个特定的程序集中载入一个特定的类.