单例的目的:仅允许程序中存在有且仅有一个实例
单例的好处:
1、对于频繁使用的对象,可以省略创建对象所需的时间。
2、减少了new对象的操作次数,降低了系统内存的使用频率,减轻了GC的压力,缩短了DC的停顿时间
- public class Singleton{
-
- private static volatile Singleton mInstance;//声明私有属性的对象
-
- private Singleton(){}//构造方法私有化
-
- public static Singleton getInstance(){//创建一个外部可以访问的公开的方法返回当前对象的实例
-
- if(mInstance == null){
-
- synchronized (Singleton.class) {
-
- if(mInstance == null){
-
- mInstance = new Singleton();
-
- }
-
- }
-
- }
-
- return mInstance;
-
- }
-
- }
调试:
- public static void getReflect() {
-
- Singleton singleton = Singleton.getInstance();
-
- try {
-
- Constructor
constructor = Singleton.class.getDeclaredConstructor(); -
- constructor.setAccessible(true);//允许访问私有构造器
-
- Singleton reflectSingleton = constructor.newInstance();
-
- System.out.println(reflectSingleton == singleton);//判断当前两个实例是否是同一个对象
-
- } catch (Exception e) {
-
- e.printStackTrace();
-
- }
-
- }
输出:false
原理解析:通过反射获得私有的构造器,通过把这个构造器的setAccessible属性设置为true,这样直接无视了构造器的私有性,我们先通过正常的getInstance()方法创建一个实例,再通过反射得到的构造器创建一个实例,
解决方案: 其思想就是采用一个全局变量,来标记是否已经实例化过了,如果已经实例化过了,第二次实例化的时候,抛出异常。
- public class Singleton{
-
- private static volatile Singleton mInstance;
-
- private static volatile boolean mIsInstantiated = false;
-
- private Singleton(){
-
- if (mIsInstantiated){
-
- throw new RuntimeException("休想反射破坏我的单例");
- }
-
- mIsInstantiated = true;
-
- }
-
- public static Singleton getInstance(){
-
- if(mInstance == null){
-
- synchronized (Singleton.class) {
-
- if(mInstance == null){
-
- mInstance = new Singleton();
-
- }
-
- }
-
- }
-
- return mInstance;
-
- }
-
- }
- public class Singleton implements Cloneable {
-
- private static volatile Singleton mInstance;
-
- private Singleton() {
-
- }
-
- public static Singleton getInstance() {
-
- if (mInstance == null) {
-
- synchronized (Singleton.class) {
-
- if (mInstance == null) {
-
- mInstance = new Singleton();
-
- }
-
- }
-
- }
-
- return mInstance;
-
- }
-
- @NonNull
-
- @Override
-
- protected Object clone() throws CloneNotSupportedException {
-
- return super.clone();
-
- }
-
- }
注意点:若要具有克隆能力,实现Cloneable接口的类必须重写从Object继承来的clone方法,并调用Object的clone方法。
- protected Object clone() throws CloneNotSupportedException {
-
- if (!(this instanceof Cloneable)) {
-
- throw new CloneNotSupportedException("Class " + getClass().getName() +
-
- " doesn't implement Cloneable");
-
- }
-
-
-
- return internalClone();
-
- }
clone方法首先会判对象是否实现了Cloneable接口,若无则抛出CloneNotSupportedException, 最后会调用internalClone. intervalClone是一个native方法。
调试:
- public static void getClone() {
-
-
- try {
-
- Singleton singleton = Singleton.getInstance();
-
- Singleton cloneSingleton;
-
- cloneSingleton = (Singleton) Singleton.getInstance().clone();
-
- System.out.println(cloneSingleton == singleton);
-
- } catch (CloneNotSupportedException e) {
-
- e.printStackTrace();
-
- }
-
- }
-
-
输出:false
原理解析:java.lang.Obeject#clone() 方法不会调用构造方法,而是直接从内存中拷贝内存区域。
解决方案:重写clone()方法,调clone()时直接返回已经实例的对象
- public class Singleton implements Cloneable {
-
- private static volatile Singleton mInstance;
-
- private Singleton() {
-
- }
-
- public static Singleton getInstance() {
-
- if (mInstance == null) {
-
- synchronized (Singleton.class) {
-
- if (mInstance == null) {
-
- mInstance = new Singleton();
-
- }
-
- }
-
- }
-
- return mInstance;
-
- }
-
-
- @NonNull
-
- @Override
-
- protected Object clone() throws CloneNotSupportedException {
-
- // return super.clone();
-
- return mInstance;//调clone()时直接返回已经实例的对象
-
- }
-
- }
- public class Singleton implements Serializable {
-
- private static volatile Singleton mInstance;
-
- private Singleton(){
-
- }
-
- public static Singleton getInstance(){
-
- if(mInstance == null){
-
- synchronized (Singleton.class) {
-
- if(mInstance == null){
-
- mInstance = new Singleton();
-
- }
-
- }
-
- }
-
- return mInstance;
-
- }
-
-
- }
很简单 实现Serializable接口就行了。
调试:
- public static void getSerializable(){
-
- try {
-
- Singleton singleton = Singleton.getInstance();
-
- FileOutputStream fos = new FileOutputStream("singleton.txt");
-
- ObjectOutputStream oos = new ObjectOutputStream(fos);
-
- oos.writeObject(singleton);
-
- oos.close();
-
- fos.close();
-
- FileInputStream fis = new FileInputStream("singleton.txt");
-
- ObjectInputStream ois = new ObjectInputStream(fis);
-
- Singleton serializedSingleton = (Singleton) ois.readObject();
-
- fis.close();
-
- ois.close();
-
- System.out.println(serializedSingleton==singleton);
-
- } catch (Exception e) {
-
- e.printStackTrace();
-
- }
-
- }
-
- }
输出:false
原理解析:在反序列化时,ObjectInputStream 因为利用反射机制调用了 readObject --> readObject0 --> readOrdinary --> CheckResolve。在readOrdinady中调用了invokeReadResolve(),该方法使用反射机制创建新的对象,从而破坏了单例唯一性。
解决方案:在反序列化时的回调方法 readResolve()中返回单例对象
- public class Singleton implements Serializable {
-
- private static volatile Singleton mInstance;
-
-
-
- private Singleton() {
-
- }
-
-
-
- public static Singleton getInstance() {
-
- if (mInstance == null) {
-
- synchronized (Singleton.class) {
-
- if (mInstance == null) {
-
- mInstance = new Singleton();
-
- }
-
- }
-
- }
-
- return mInstance;
-
- }
-
-
-
- protected Object readResolve() throws ObjectStreamException {
-
- return mInstance;
-
- }
-
- }