今天电话面试的时候问到了,Google了一下

原出处:

http://blog.csdn.net/lws332969674/article/details/8125893

一、 Java中的反射技术可以获取类的所有方法、成员变量、还能访问private的构造方法,这样一来,单例模式中用的私有构造函数被调用就会产生多个实例,编写代码测试一下。

  1. package test;
  2. import java.lang.reflect.Constructor;
  3. public class SingetonTest {
  4. private static SingetonTest singleton = null;
  5. private int s = 0;
  6. // 构造方法是私有的
  7. private SingetonTest(){}
  8. // 同步的获取实例方法
  9. public static synchronized SingetonTest getInstance(){
  10. // 懒汉模式的单例方法
  11. if(null == singleton){
  12. singleton = new SingetonTest();
  13. }
  14. return singleton;
  15. }
  16. public int getS() {
  17. return s;
  18. }
  19. public void setS(int s) {
  20. this.s = s;
  21. }
  22. /**
  23. * @param args
  24. */
  25. public static void main(String[] args) {
  26. try {
  27. Constructor con = SingetonTest.class.getDeclaredConstructor();
  28. con.setAccessible(true);
  29. // 通过反射获取实例
  30. SingetonTest singetonTest1 = (SingetonTest)con.newInstance();
  31. SingetonTest singetonTest2 = (SingetonTest)con.newInstance();
  32. // 常规方法获取实例
  33. SingetonTest singetonTest3 = SingetonTest.getInstance();
  34. SingetonTest singetonTest4 = SingetonTest.getInstance();
  35. // 测试输出
  36. System.out.println("singetonTest1.equals(singetonTest2) :" +  singetonTest1.equals(singetonTest2));
  37. System.out.println("singetonTest3.equals(singetonTest4) :" +  singetonTest3.equals(singetonTest4));
  38. System.out.println("singetonTest1.equals(singetonTest3) :" +  singetonTest1.equals(singetonTest3));
  39. singetonTest1.setS(1);
  40. singetonTest2.setS(2);
  41. singetonTest3.setS(3);
  42. singetonTest4.setS(4);
  43. System.out.println("1:" + singetonTest1.getS() + "  2:" + singetonTest2.getS()+ "  3:" + singetonTest3.getS()+ "  4:" + singetonTest4.getS());
  44. } catch (Exception e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. }
  49. }

测试结果:

singetonTest1.equals(singetonTest2) :false
singetonTest3.equals(singetonTest4) :true
singetonTest1.equals(singetonTest3) :false
1:1  2:2  3:4  4:4

通过反射技术生成的两个实例不同,通过常规方法获取的两个实例相同(即同一个实例,单例)。

二、防止反射破坏单例模式,构造函数调用时进行处理,当构造函数第2次被调用时抛出异常!修改构造方法如下:

  1. private static boolean flag = false;
  2. // 构造方法是私有的
  3. private SingetonTest(){
  4. if(flag){
  5. flag = !flag;
  6. }
  7. else{
  8. try {
  9. throw new Exception("duplicate instance create error!" + SingetonTest.class.getName());
  10. } catch (Exception e) {
  11. // TODO Auto-generated catch block
  12. e.printStackTrace();
  13. }
  14. }
  15. }

三、一些思考

1)单例模式是为了保证一个类只有一个实例,整个系统只能有自己创建的一个实例。应用在数据库连接或单个队列处理等问题。

2)单例模式构造,懒汉模式以时间换空间(用的时候才生产实例,每次都判断);懒汉模式以空间换时间,直接创建实例,以后不用判断直接用。

3)懒汉模式线程安全问题,获取实例的方法要加上synchronized进行同步。

4)java的反射技术不要用于实例创建,反射主要用于Spring的IOC, Hibernate和白盒测试。

---------------------------------------------------------我是枚举分割线-------------------------------------------------------

可以用枚举防止反射破坏单例模型(PS:JAVA 枚举是线程安全的)

From:http://blog.csdn.net/tounaobun/article/details/8514989

JDK1.5及以后,增加了实现Singleton的第三种方法。只需编写一个包含单个元素的枚举类型。

  1. public enum Adam {
  2. INSTANCE;   //只有一个元素
  3. public void leaveTheBuilding() {;;;}
  4. }

使用这种方法的好处是可以防止多次实例化,无偿提供了序列化机制,即使是面对复杂的序列化或者反射公鸡。

当你试图通过反射调用枚举类型的构造器时(默认构造器为private),如果调用了setAccessible(true)方法,将会抛出IllegalArgumentException:

  1. Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
  2. at java.lang.reflect.Constructor.newInstance(Unknown Source)
  3. at org.reflect.Test.main(Test.java:23)

对于前两种单例模式,为了使Singleton能够序列化,除了实现标记接口Serializable外,还需增加类似下面的方法,防止反序列化时生成“假冒”的单例类:

  1. private Object readResolve() {
  2. return INSTANCE;
  3. }

而对于枚举类型,完全不用多此一举。因为枚举类型已经提供了该机制。

Java反射破坏单例模式的更多相关文章

  1. Java设计模式之单例模式理解

    前言 本片博客主要记录Java23种设计模式中的创建型模式中的单例模式.单例模式可分为两类,一种是饿汉式,一种是懒汉式.饿汉式的三种设计方式(静态变量方式.静态代码块方式.枚举方式),懒汉式(单锁检查 ...

  2. 初识Java反射机制

    1.ClassLoader的类加载机制:并非一次性加载,而是需要的时候加载(运行期间动态加载)(Class文件加载到内存的代码段),static语句块在加载后执行一次.dynamic语句块(就是一个语 ...

  3. Java设计模式之单例模式详解

    在Java开发过程中,很多场景下都会碰到或要用到单例模式,在设计模式里也是经常作为指导学习的热门模式之一,相信每位开发同事都用到过.我们总是沿着前辈的足迹去做设定好的思路,往往没去探究为何这么做,所以 ...

  4. [java设计模式]之单例模式

    -------------------此部分比較深入地解说了单例模式,原文链接已给出.兴许将涉及一些常见面试问题--------------------------- 原文地址:http://www. ...

  5. Java 反射获取私有方法

    通常我们创建一个类时,它的私有方法在类外是不可见的,但是可以通过反射机制来获取调用.具体的反射机制的介绍大家自己百度. 所以反射可能会破坏我们的单例模式,当然解决方案也是有的,就是做个标记记录次数,第 ...

  6. java设计模式1——单例模式

    java设计模式1--单例模式 1.单例模式介绍 1.1.核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 1.2.常见场景 1.3.单例模式的优点 1.4.常见的五种单例模式实现 ...

  7. java设计模式之单例模式你真的会了吗?(懒汉式篇)

    java设计模式之单例模式你真的会了吗?(懒汉式篇) 一.什么是单例模式? 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供 ...

  8. 浅析Java反射--Java

    前言 上篇文章我们提到了可以使用反射机制破解单例模式.这篇文章我们就来谈一谈什么是反射,反射有什么用,怎么用,怎么实现反射. 概述 Java的反射(reflection)机制:是指在程序的运行状态中, ...

  9. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

随机推荐

  1. java线程池的使用(转)

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  2. SQL Server 附加数据库 错误5210

    前言 那天在弄机房的时候,附加数据库总是附加不上,然而将附加数据库文件放到优盘里,就可以附加成功.我也不知道为什么了,但是这次还是别将就了.于是乎,上网查了查原来是权限不够啊.这可怎么办,见下面三种方 ...

  3. [Swift实际操作]九、完整实例-(6)创建App欢迎界面

    本文创建一个位于导航控制器之内的欢迎页面,该页面主要用来向用户简要介绍产品的功能.以及提供主要功能的入口. 首先选择自定义视图文件夹[CustomViews],需要在该文件夹下,导入一款第三方类库.该 ...

  4. C语言数据结构-顺序线性表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作

    1.数据结构-顺序线性表的实现-C语言 #define MAXSIZE 100 //结构体定义 typedef struct { int *elem; //基地址 int length; //结构体当 ...

  5. linux下mysql的安装部署

    ---恢复内容开始--- 注意这一切都是root用户下进行的 su root  * 一.查看之前是否安装过:yum list installed mysql* 二.查看是否有安装包:yum list ...

  6. Qt 学习之路 2(12):菜单栏、工具栏和状态栏

    Home / Qt 学习之路 2 / Qt 学习之路 2(12):菜单栏.工具栏和状态栏 Qt 学习之路 2(12):菜单栏.工具栏和状态栏  豆子  2012年9月10日  Qt 学习之路 2  2 ...

  7. 写一个Spring Boot的Hello World

    尽管这个demo也就hello world水平,但我还是要记录一下(总算能动了QAQ),毕竟老是看文章不动手不行啊 上次写Servlet的CRUD项目还是2月份,虽然代码忘的差不多了,但我就记得JDB ...

  8. Java快速IO(ACM)必备

    en.... 无非用到的是 1. new Scanner(System.in); 2.new BUfferReader(new InputStreamReader(System.in); 3.Syst ...

  9. [Android UI]View滑动方式总结

    一.前言 在上一篇文章,介绍了View的坐标等基础知识,有了基础知识后,对下面内容的理解也将会容易很多.那么本文介绍的是View滑动的几种方式,这对于View来说,也是需要重要掌握的内容,因为用户无时 ...

  10. C语言中类型限定符

    通常用类型和存储类别来描述一个变量. C90还增加了两个属性:恒常性(constancy).易变性(volatility): 分别用关键字const和volatile来声明. 这两个关键字创建的类型是 ...