Java反射破坏单例模式
今天电话面试的时候问到了,Google了一下
原出处:
http://blog.csdn.net/lws332969674/article/details/8125893
一、 Java中的反射技术可以获取类的所有方法、成员变量、还能访问private的构造方法,这样一来,单例模式中用的私有构造函数被调用就会产生多个实例,编写代码测试一下。
- package test;
- import java.lang.reflect.Constructor;
- public class SingetonTest {
- private static SingetonTest singleton = null;
- private int s = 0;
- // 构造方法是私有的
- private SingetonTest(){}
- // 同步的获取实例方法
- public static synchronized SingetonTest getInstance(){
- // 懒汉模式的单例方法
- if(null == singleton){
- singleton = new SingetonTest();
- }
- return singleton;
- }
- public int getS() {
- return s;
- }
- public void setS(int s) {
- this.s = s;
- }
- /**
- * @param args
- */
- public static void main(String[] args) {
- try {
- Constructor con = SingetonTest.class.getDeclaredConstructor();
- con.setAccessible(true);
- // 通过反射获取实例
- SingetonTest singetonTest1 = (SingetonTest)con.newInstance();
- SingetonTest singetonTest2 = (SingetonTest)con.newInstance();
- // 常规方法获取实例
- SingetonTest singetonTest3 = SingetonTest.getInstance();
- SingetonTest singetonTest4 = SingetonTest.getInstance();
- // 测试输出
- System.out.println("singetonTest1.equals(singetonTest2) :" + singetonTest1.equals(singetonTest2));
- System.out.println("singetonTest3.equals(singetonTest4) :" + singetonTest3.equals(singetonTest4));
- System.out.println("singetonTest1.equals(singetonTest3) :" + singetonTest1.equals(singetonTest3));
- singetonTest1.setS(1);
- singetonTest2.setS(2);
- singetonTest3.setS(3);
- singetonTest4.setS(4);
- System.out.println("1:" + singetonTest1.getS() + " 2:" + singetonTest2.getS()+ " 3:" + singetonTest3.getS()+ " 4:" + singetonTest4.getS());
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
测试结果:
singetonTest1.equals(singetonTest2) :false
singetonTest3.equals(singetonTest4) :true
singetonTest1.equals(singetonTest3) :false
1:1 2:2 3:4 4:4
通过反射技术生成的两个实例不同,通过常规方法获取的两个实例相同(即同一个实例,单例)。
二、防止反射破坏单例模式,构造函数调用时进行处理,当构造函数第2次被调用时抛出异常!修改构造方法如下:
- private static boolean flag = false;
- // 构造方法是私有的
- private SingetonTest(){
- if(flag){
- flag = !flag;
- }
- else{
- try {
- throw new Exception("duplicate instance create error!" + SingetonTest.class.getName());
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
三、一些思考
1)单例模式是为了保证一个类只有一个实例,整个系统只能有自己创建的一个实例。应用在数据库连接或单个队列处理等问题。
2)单例模式构造,懒汉模式以时间换空间(用的时候才生产实例,每次都判断);懒汉模式以空间换时间,直接创建实例,以后不用判断直接用。
3)懒汉模式线程安全问题,获取实例的方法要加上synchronized进行同步。
4)java的反射技术不要用于实例创建,反射主要用于Spring的IOC, Hibernate和白盒测试。
---------------------------------------------------------我是枚举分割线-------------------------------------------------------
可以用枚举防止反射破坏单例模型(PS:JAVA 枚举是线程安全的)
From:http://blog.csdn.net/tounaobun/article/details/8514989
JDK1.5及以后,增加了实现Singleton的第三种方法。只需编写一个包含单个元素的枚举类型。
- public enum Adam {
- INSTANCE; //只有一个元素
- public void leaveTheBuilding() {;;;}
- }
使用这种方法的好处是可以防止多次实例化,无偿提供了序列化机制,即使是面对复杂的序列化或者反射公鸡。
当你试图通过反射调用枚举类型的构造器时(默认构造器为private),如果调用了setAccessible(true)方法,将会抛出IllegalArgumentException:
- Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
- at java.lang.reflect.Constructor.newInstance(Unknown Source)
- at org.reflect.Test.main(Test.java:23)
对于前两种单例模式,为了使Singleton能够序列化,除了实现标记接口Serializable外,还需增加类似下面的方法,防止反序列化时生成“假冒”的单例类:
- private Object readResolve() {
- return INSTANCE;
- }
而对于枚举类型,完全不用多此一举。因为枚举类型已经提供了该机制。
Java反射破坏单例模式的更多相关文章
- Java设计模式之单例模式理解
前言 本片博客主要记录Java23种设计模式中的创建型模式中的单例模式.单例模式可分为两类,一种是饿汉式,一种是懒汉式.饿汉式的三种设计方式(静态变量方式.静态代码块方式.枚举方式),懒汉式(单锁检查 ...
- 初识Java反射机制
1.ClassLoader的类加载机制:并非一次性加载,而是需要的时候加载(运行期间动态加载)(Class文件加载到内存的代码段),static语句块在加载后执行一次.dynamic语句块(就是一个语 ...
- Java设计模式之单例模式详解
在Java开发过程中,很多场景下都会碰到或要用到单例模式,在设计模式里也是经常作为指导学习的热门模式之一,相信每位开发同事都用到过.我们总是沿着前辈的足迹去做设定好的思路,往往没去探究为何这么做,所以 ...
- [java设计模式]之单例模式
-------------------此部分比較深入地解说了单例模式,原文链接已给出.兴许将涉及一些常见面试问题--------------------------- 原文地址:http://www. ...
- Java 反射获取私有方法
通常我们创建一个类时,它的私有方法在类外是不可见的,但是可以通过反射机制来获取调用.具体的反射机制的介绍大家自己百度. 所以反射可能会破坏我们的单例模式,当然解决方案也是有的,就是做个标记记录次数,第 ...
- java设计模式1——单例模式
java设计模式1--单例模式 1.单例模式介绍 1.1.核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 1.2.常见场景 1.3.单例模式的优点 1.4.常见的五种单例模式实现 ...
- java设计模式之单例模式你真的会了吗?(懒汉式篇)
java设计模式之单例模式你真的会了吗?(懒汉式篇) 一.什么是单例模式? 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供 ...
- 浅析Java反射--Java
前言 上篇文章我们提到了可以使用反射机制破解单例模式.这篇文章我们就来谈一谈什么是反射,反射有什么用,怎么用,怎么实现反射. 概述 Java的反射(reflection)机制:是指在程序的运行状态中, ...
- java设计模式之单例模式(几种写法及比较)
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
随机推荐
- Win10每次开机总是自动弹出MSN网址导航如何取消
Win10每次开机总是自动弹出MSN网址导航如何取消 近来有用户在升级Win10系统后,每次开机总是会自动弹出MSN中文网的网址导航.如果不想要开机打开MSN网址导航,那么应该怎么设置来取消呢?对此, ...
- 51nod1478(yy)
题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1478&judgeId=365133 题意: 中文题诶 ...
- Ubuntu安装SHH服务
1.打开"终端窗口",输入"sudo apt-get update"-->回车-->"输入当前登录用户的管理员密码"--> ...
- 14.链表中倒数第k个节点
题目描述: 输入一个链表,输出该链表中倒数第k个结点. 思路分析: 设置两个指针,一个fast一个slow,都从链表头开始,让fast先走k步,然后两个指针一起走,当fast走到尾部,那么sl ...
- git基础命令整理
首先安装git,然后选择一个文件夹做初始化!! yum -y install git ### 安装 git init ...
- java 的开发工具IDEA使用 中Debug 调试工具使用
IDEA JetBrains(这个公司的名称翻译过来就是“大脑喷射?”) 公司的宣传语是这么说的:Develop with pleasure!(带着快乐开发!) 话不多说 开始debug 1, ...
- hdu3483 A Very Simple Problem 非线性递推方程2 矩阵快速幂
题目传送门 题目描述:给出n,x,mod.求s[n]. s[n]=s[n-1]+(x^n)*(n^x)%mod; 思路:这道题是hdu5950的进阶版.大家可以看这篇博客hdu5950题解. 由于n很 ...
- 关于string 的简单应用
声明||作用 string类本不是STL的容器,但是它与STL容器有着很多相似的操作,因此,把string放在这里一起进行介绍. 之所以抛弃char*的字符串而选用C++标准程序库中的string类, ...
- linux输入输出及vim管理
一.理解系统的输入输出 输入输出系统是计算机重要组成部分,是沟通计算机与外界的桥梁. 二.管理输入输出的符号 1.输出重定向 > ##重定向正确输出 ...
- http协议&接口规范&接口测试入门
http协议 请求: 请求行:请求方法.url(协议名://ip;端口/工程名/资源路径).协议版本 请求头 :键值对 请求正文 响应: 响应行:协议版本.响应状态码.响应状态码描述 响应头 :键值对 ...