终结者单身——setAccessible(true)
首先看一下“传说”Singleton模式
package go.derek;
public class Singleton{
public static int times;
private Singleton(){
//构造器被调用的时候会打印出次数
System.out.println("单例构造器被调用"+(++times)+"两次");
}
private final static Singleton instance=new Singleton();
public static Singleton getInstance(){
return instance;
}
public void doSomething(){
System.out.println("do something");
}
}
以下是測试类主函数:
package go.derek; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; public class Test {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//通过单例模式获得单例对象obj1
Singleton obj1=Singleton.getInstance();
//运行一次doSomething方法
obj1.doSomething();
//观察控制台,这次获得的obj2对象跟obj1是同一个单例。没有调用构造器
Singleton obj2=Singleton.getInstance();
obj2.doSomething();
//以下厉害的来了,首先拿到万能的Class对象
Class<Singleton> clazz=Singleton.class;
//然后拿到构造器。使用这种方法私有的构造器也能够拿到
Constructor<Singleton> c=clazz.getDeclaredConstructor();
//设置在使用构造器的时候不运行权限检查
c.setAccessible(true);
//因为没有了权限检查。所以在Singleton类外面也能够创建对象了,然后运行方法
//观察控制台,私有构造器又被调用了一次,单例模式被攻陷了,运行方法成功。 c.newInstance().doSomething();
}
}
执行结果例如以下:
单例构造器被调用1两次
do something
do something
单例构造器被调用2两次
do something
试想一下,假设某个恶意client通过上面的方式。就能够为所欲为了。所以为了避免出现这样的情况,能够再构造器被第二次调用的时候抛出一个异常
package go.derek;
public class Singleton{
public static int times;
private Singleton() {
//构造器被调用的时候会打印出次数
System.out.println("单例构造器被调用"+(++times)+"两次");
if(instance!=null){
throw new IllegalArgumentException("单例构造器不能反复使用");
}
}
private final static Singleton instance=new Singleton();
public static Singleton getInstance(){
return instance;
}
public void doSomething(){
System.out.println("do something");
}
}
执行结果例如以下:
单例构造器被调用1两次
do something
do something
单例构造器被调用2两次
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at go.derek.Test.main(Test.java:24)
Caused by: java.lang.IllegalArgumentException: 单例构造器不能反复使用
at go.derek.Singleton.<init>(Singleton.java:10)
... 5 more
目标实现~
版权声明:本文博客原创文章,博客,未经同意,不得转载。
终结者单身——setAccessible(true)的更多相关文章
- Java 反射 getDeclareFields getModifiers setAccessible(true)
示例代码: public static Map<String, Object> dtoToMap(Object obj, String pre, String las ...
- field.setAccessible(true) 简介
今天查看别人写的代码时,发现这样一句代码,顿时来了兴趣. 需要注意setAccessible 并不是在Field中的,而是在AccessibleObject中. 下面是AccessibleObject ...
- 提高java反射速度的方法method.setAccessible(true)
转载:http://huoyanyanyi10.iteye.com/blog/1317614 提高java反射速度的方法method.setAccessible(true) package com.c ...
- [转载] 在java中为什么变量1000 = 1000 返回false,但是100=100返回true?
ps:题目的意思是指定义相同内容的不同变量之间的==比较.如果直接比较(100 == 100)的结果是true. 运行以下代码: Integer a = 1000, b = 1000; System. ...
- Java中1000==1000为false而100==100为true
public static void main(String[] args) { int z1 = 0; int z2 = 0; System.out.println(z1==z2);//TRUE I ...
- Java 反射 调用私有域和方法(setAccessible)
Java 反射 调用私有域和方法(setAccessible) @author ixenos AccessibleObject类 Method.Field和Constructor类共同继承了Acces ...
- 为什么Java 两个Integer 中1000==1000为false而100==100为true?
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt346 这是一个挺有意思的讨论话题. 如果你运行下面的代码 1 2 3 4 I ...
- 反射setAccessible()方法
java代码中,常常将一个类的成员变量置为private 在类的外面获取此类的私有成员变量的value时,需要注意: 测试类: public class AccessibleTest { privat ...
- 奇怪的Java题:为什么1000 == 1000返回为False,而100 == 100会返回为True?
如果你运行如下代码: 1 2 3 4 Integer a = 1000, b = 1000; System.out.println(a == b);//1 Integer c = 100, d = ...
随机推荐
- Codeforces 61E Enemy is weak 乞讨i<j<k && a[i]>a[j]>a[k] 对数的 树阵
主题链接:点击打开链接 意大利正在寻求称号 i<j<k && a[i]>a[j]>a[k] 的对数 假设仅仅有2元组那就是求逆序数的做法 三元组的话就用一个树状 ...
- WebKit爬虫
https://github.com/emyller/webkitcrawler 一个开源的项目,可以快速入门. http://spiderformysql.com/ http://crawl.gro ...
- hdu4714(树形dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4714 题意:给你一棵树,,其中每去掉一条边或加一条边的代价均为1,让你求出将其变成一个圆的最小代价. ...
- [Sqlite] 移动嵌入式数据库Sqlite日报SQL操作语句汇总
,EXPLAIN分析 没有建立索引之前.分析都是表扫描: sqlite> EXPLAIN SELECT * FROM COMPANY WHERE Salary < 20000; add ...
- sql语句中 limi的用法
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset 使用查询语句时需要返回前几条或者中间的某几行数据时可以用到limit 例如 ...
- 字符串匹配的KMP算法(转)
字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...
- php-GD库的函数(二)
<?php //imagecopy — 拷贝图像的一部分粘贴到某图像上 /*bool imagecopy ( resource $dst_im , resource $src_im , int ...
- atitit查询表改动表字段没反应--解锁锁定的表
atitit查询表改动表字段没反应--解锁锁定的表 查询表改动表字段没反应 要是使用gui 没反应,最好使用cmd 方式,不卉不个gui 锁上.. ALTER TABLE t_mb_awardweix ...
- Google Earth数据存储、管理、表现及开发机制
Google Earth数据存储.管理.表现及开发机制 一. Google Earth(Map)介绍 1.1 Google Earth介绍 在众多的地理信息服务提供商中,Google是较早 ...
- 游戏开发实验室的内部讲座总结----c++
第三节 动态内存分配new和delete 经过调试设置断点,发现new 函数事实上还是调用的malloc函数. 第四节 引用 一个变量是能够有多个引用的,引用也是能够传递的. 常量是不能有 ...