I want to fly higher
programming Explorer
BlogJava
首页
新随笔
新文章
联系
聚合
管理
posts - 114,comments - 263,trackbacks - 0
<
2013年3月
>
日
一
二
三
四
五
六
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
6
常用链接
我的随笔
我的文章
我的评论
我的参与
最新评论
留言簿
(5)
给我留言
查看公开留言
查看私人留言
随笔分类
(161)
Book(25)
ClassLoader(5)
Concurrency
Dababase
GameServer(10)
HighPerformance
HotSwap(9)
IO
JVM(6)
Language(2)
Mobile
NetWork(2)
NoSQL
Note(8)
OS(6)
Program(69)
Script(1)
ServerFramework(6)
Shell
Sources(8)
Translations
Utils(4)
随笔档案
(114)
2018年6月 (1)
2018年3月 (1)
2017年3月 (2)
2017年2月 (2)
2017年1月 (1)
2016年11月 (2)
2016年7月 (4)
2016年6月 (3)
2016年5月 (2)
2015年12月 (2)
2015年10月 (1)
2015年8月 (1)
2015年7月 (4)
2015年6月 (5)
2014年12月 (1)
2014年11月 (4)
2014年4月 (1)
2014年3月 (3)
2014年2月 (5)
2014年1月 (1)
2013年12月 (7)
2013年11月 (4)
2013年8月 (5)
2013年7月 (3)
2013年3月 (6)
2013年1月 (6)
2012年7月 (1)
2011年12月 (9)
2011年8月 (2)
2011年5月 (1)
2011年2月 (2)
2011年1月 (1)
2010年12月 (2)
2010年11月 (1)
2010年7月 (8)
2010年4月 (3)
2010年3月 (3)
2010年2月 (2)
2010年1月 (2)
文章分类
(2)
学习笔记(2)
文章档案
(2)
2011年12月 (2)
Alibaba
搜索技术博客-淘宝
淘宝开源项目
阿里中间件团队博客
阿里技术嘉年华
阿里核心系统团队博客
Comprehensive
InfoQ - 促进软件开发领域知识与创新的传播
LinkedIn
stackoverflow
伯乐在线
内存-溢出 为程序员服务
腾讯大讲堂
解道
Expert
jrebel
国外牛博
并发编程高手
庄周梦蝶
洞庭散人
美团技术博客
褚霸
Game
云风
Java
JavaEye做最棒的软件开发交流社区
coderanch
IBM developerWorks 中国 Java 技术专区
Java Tutorials
Javalobby
javapapers
java-source
java-tips
javaworld
Java极客
Java译站
Programming Tutorial
TheServerSide
专注Java & Android 技术分享
并发编程网
搜索
积分与排名
积分 - 597364
排名 - 78
最新评论
1. re: Eclipse反编译工具Jad及插件JadClipse配置
刚刚问题解决了,file types中, .class下还有一个 .class without source。
把这个也设置成JadClipse为默认选项打开嘛,即可。
谢谢版主~~~
--tangyuan
2. re: Eclipse反编译工具Jad及插件JadClipse配置
eclipse4.6版本,按照上述来的不行,版主还有推荐的反编工具嘛,推荐一个呢
--tangyuan
3. re: 交换两个值,不用临时变量(C位运算)[未登录]
评论内容较长,点击标题查看
--123
4. re: Markdown基础语法及发布blog
确实很基础的语法,很容易就学会了!
--有机绿茶
5. re: Java8之Stream/Map[未登录]
总结的很详细!
--jay
阅读排行榜
1. Eclipse反编译工具Jad及插件JadClipse配置(134317)
2. Unknown Source的出现及解决(39299)
3. MMORPG服务器架构(33406)
4. Java8之Stream/Map(24519)
5. 浅谈Eclipse dropins插件安装的"坑"(附m2e的各个版本插件下载)(19587)
Effective Java 2nd笔记3:用私有构造器或者枚举类型强化Singleton属性
第三条:用私有构造器或者枚举类型强化Singleton属性
1.
Singleton指仅仅被实例化一次的类
。Singleton通常被用来代表那些本质上唯一的系统组件,如窗口管理器或者文件系统。使类称为Singleton会使它的客户端调试变的十分困难,因为无法给Singleton替换模拟实现,除非它实现一个充当其类型的接口.
2.在
Java1.5发行版本之前,实现Singleton有两种方法
。这两种方法都要把构造器保持为私有,并导出公有的静态成员,以便客户端能够访问该类的唯一实例,以便允许client能够访问该类的唯一实例。
3.第一种方法中,公有静态成员是个final域:
public class Singleton1
{
public static final Singleton1 INSTANCE = new Singleton1();
//私有改造函数
private Singleton1()
{
}
//其他方法实现
public void otherMethod()
{
//...
}
}
私有构造器仅被调用一次,用来实例化公有的静态final域Singleton1.INSTANCE.由于缺少公有的或者受保护的构造器,所以保证了Singleton1的全局唯一性。一旦其被实例化,只会存在一个实例,不多也不少。客户端的任何行为都不会改变这一点。
注
:享有特权的client可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。如果要抵御这种攻击,需要修改构造器,让其在创建第二个实例的时候抛出异常。
4.在实现Singleton的第二种方法中,公有的成员是个静态工厂方法:
public class Singleton2
{
//私有static Instance
private static final Singleton2 INSTANCE = new Singleton2();
//私有构造函数
private Singleton2()
{
}
//获取单例方法
public static Singleton2 getInstance()
{
return INSTANCE;
}
//其他方法
public void otherMethod()
{
//...
}
}
对于静态方法Singleton2.getInstance的所有调用,都会返回同一个对象引用,所以永远不会创建其他的实例。
注
:上述利用反射的提醒依然适用。
5.公有域方法的好处在于,组成类的成员的声明很清楚的表明了这个类是一个Singleton(final),公有的静态域是final的,所以该域将总是包含相同的对象引用。公有域方法在性能上不再有任何优势:现在JVM实现几乎都能都将静态工厂方法的调用内联化。
注:内联
:指函数在被调用的地方直接展开,编译器在调用时不用像一般函数那样,参数压栈,返回时参数出栈以及资源释放等,这样提高了程序执行速度.
6.工厂方法的
优势
在于,它提供了灵活性:在不改变其API的前提下,我们可以改变该类是否为Singleton的想法。工厂方法返回该类的唯一实例,不过它可以很容易被修改,如改成为每个调用该方法的线程返回一个唯一的实例。
第二个优势在于与
泛型
有关。
这些优势之间通常不相关,public域的方法比较简单.
7.以上的两种的其中一种方法实现的Singleton类如果变成是可
序列化
的Serialiazble,仅仅在声明加上implements Serializable是不够的。为了维护并保证Singleton,必须声明所有实例都是瞬时transient的,并提供 一个readResolve方法。否则每次反序列化一个序列化的实例时,都会创建一个新的实例。即会导致一个假冒的对象。为了防止这种情况,需要在单例类中增加readResolve方法->
注:readResolve
方法用来重新指定反序列化得到的对象.
private Object readResolve()
{
return INSTANCE;
}
8.
从Java 1.5发行版本起,实现Singleton还有第三种方法。只需编写一个包含单个元素的枚举类型。
public Enum Singleton3
{
INSTANCE;
public void otherMethod()
{
}
}
这种方法在功能上与公有域方法相近,但是其更加简洁,无偿提供了序列化机制,绝对防止多次实例化,即使是面对复杂的序列化或者反射攻击的时候。 虽然这种方法还没有广泛使用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。
注:用反射调用私有构造函数:报错:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects.
ps:枚举真心不错.
部分源码:
package
com.book.chap2.singleton;
import
java.lang.reflect.Constructor;
/** */
/**
*
* 单例实现1
* <p>
* 公有静态成员是个public final域
* <p>
* 为防止client利用反射调用私有改造函数,所以在创建第二个实例的时候抛出了异常
*
*
@author
landon
*
@since
1.6.0_35
*
@version
1.0.0 2013-1-9
*
*/
public
class
Singleton1
{
public
static
final
Singleton1 instance
=
new
Singleton1();
//
私有改造函数
private
Singleton1()
{
if
(instance
!=
null
)
{
throw
new
IllegalArgumentException(
"
No exist the second instance
"
);
}
}
//
其他方法实现
public
void
otherMethod()
{
//
System.out.println(
"
call otherMethod
"
);
}
@SuppressWarnings(
"
rawtypes
"
)
public
static
void
main(String
args)
throws
Exception
{
Singleton1 singleton
=
Singleton1.instance;
singleton.otherMethod();
//
利用反射调用私有构造器
Constructor[] arrayConstructor
=
singleton.getClass()
.getDeclaredConstructors();
for
(Constructor constructor : arrayConstructor)
{
//
调用setAccessible(true);
constructor.setAccessible(
true
);
//
实例化,这里一定会抛出异常
constructor.newInstance();
}
}
}
package
com.book.chap2.singleton;
import
java.io.Serializable;
/** */
/**
*
*单例实现2
*<p>公有的成员为静态工厂方法
*<p>序列化时,要实现readResolve方法,防止反序列化出新的实例
*
*
@author
landon
*
@since
1.6.0_35
*
@version
1.0.0 2013-1-9
*
*/
public
class
Singleton2
implements
Serializable
{
//
私有static Instance
private
static
final
Singleton2 INSTANCE
=
new
Singleton2();
//
私有构造函数
private
Singleton2()
{
}
//
获取单例方法
public
static
Singleton2 getInstance()
{
return
INSTANCE;
}
//
其他方法
public
void
otherMethod()
{
//
}
//
必须提供该方法,以便重新指定反序列化得到的对象.
private
Object readResolve()
{
return
INSTANCE;
}
}
package
com.book.chap2.singleton;
import
java.lang.reflect.Constructor;
/** */
/**
*
*枚举实现单例
*<p>目前最好的方式,避免了反射的攻击和序列化的问题
*
*<pre>
*反射调用枚举私有构造函数测试结果:
* Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.book.chap2.singleton.Singleton3.main(Singleton3.java:34)
*</pre>
*
*
@author
landon
*
@since
1.6.0_35
*
@version
1.0.0 2013-1-9
*
*/
public
enum
Singleton3
{
INSTANCE;
public
void
otherMethod()
{
}
public
static
void
main(String
args)
throws
Exception
{
//
测试,是否可以反射生成枚举
//
利用反射调用私有构造器
Constructor[] arrayConstructor
=
Singleton3.INSTANCE.getClass().ge
tDeclaredConstructors();
for
(Constructor constructor : arrayConstructor)
{
//
调用setAccessible(true);
constructor.setAccessible(
true
);
//
实例化,这里一定会抛出异常
constructor.newInstance();
}
}
}
posted on 2013-03-15 15:38
landon
阅读(2502)
评论(2)
编辑
收藏
所属分类:
Program
、
Book
FeedBack:
#
re: Effective Java 2nd笔记3:用私有构造器或者枚举类型强化Singleton属性
2013-03-16 10:49 |
背道而驰
注:享有特权的client可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。如果要抵御这种攻击,需要修改构造器,让其在创建第二个实例的时候抛出异常。
请问楼主啊,如果判断是第二次创建实例?
回复
更多评论
#
re: Effective Java 2nd笔记3:用私有构造器或者枚举类型强化Singleton属性
2013-03-16 11:08 |
背道而驰
刚才看了后面晓得了,谢谢楼主的分享!!
回复
更多评论
新用户注册
刷新评论列表
只有注册用户
登录
后才能发表评论。
网站导航:
博客园
IT新闻
知识库
C++博客
博问
管理
相关文章:
Java游戏服务器基础技术体系
Disruptor入门Ⅰ-Getting Started
Rust/Go/Node.js/Io.js/Groovy/Scala/Lua 语言入门 Ⅰ
Vertx VS Undertow Ⅰ
Java多线程笔记9-InheritableThreadLocal
Java8之Time/Annotation
Java8之Stream/Map
Java8之Lambda
apache-mina-2.07源码笔记6-nio细节
Java多线程笔记8-ThreadLocal