郑州网站关键词优化外包,广州站是不是广州火车站,四川住房城乡建设厅网站首页,阿坝网站制作透视变换–鸟瞰图几天前#xff0c;当我回到家乡时#xff0c;我的一位来自同事的准青年参加了一家跨国公司的采访#xff0c;在采访过程中受了重伤。 我的意思是#xff0c;由于面试小组提出了一些难题#xff0c;他无法使面试合格。 当我回到班加罗尔时#xff0c;他分… 透视变换–鸟瞰图 几天前当我回到家乡时我的一位来自同事的准青年参加了一家跨国公司的采访在采访过程中受了重伤。 我的意思是由于面试小组提出了一些难题他无法使面试合格。 当我回到班加罗尔时他分享了他在技术面试中遇到的尴尬处境。 根据他今天的经验我正在撰写有关Singleton设计模式的文章。 顺便说一下我的下级同事在Java方面拥有近四年的经验。 他面临的一个有争议的问题是“ 什么是Singleton设计模式您将如何编写健壮的Singleton类 ”但是让我给您提供在项目/产品开发时经常使用的Singleton设计模式的基本和关键轮廓。 如您所知Singleton设计模式属于“ Creational Pattern ”类别。 基本原则说在任何时间点一个类都应该只有一个实例而与一个类的多次调用无关。 该原理背后有许多概念和设计。 许多开发人员采用不同的方式在Java中实现Singleton。 一些开发人员根本不喜欢这种设计。 但是我们应该专注于这种设计而其他因素对我们来说则完全不相关。 让我们从各种角度分析此设计。 技术性 正如我已经提到的将有一个类的实例让我们看下面的代码。 package com.ddlab.rnd.patterns;
public class SingletonType1
{private static SingletonType1 instance null;private SingletonType1(){super();}public static SingletonType1 getInstance(){if( instance null )instance new SingletonType1();return instance;}
} 要使用和实现我们必须编写以下代码。 SingletonType1 instance SingletonType1.getInstance(); 很好似乎是正确的。 如果您编写10次以上的代码您将获得相同的实例。 检查以上程序的正确性。 让我们做一个基本的临床测试。 通过调用代码“ SingletonType1.getInstance”来创建上述类的实例并将所有实例放入Set中。 如您所知Set不允许重复。 因此最后如果获得集合1的大小则它是正确的实现。 您也可以。 肯定会得到结果为1即Set的大小。 现在我们想到了一个问题我们可以打破以上设计吗 是否可以创建上述定义的类的多个实例 是。 我们可以。 我们可以打破以上设计并且可以创建多个实例。 那个怎么样 让我们看下面的代码。 package com.ddlab.rnd.patterns;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class TestSingletonType1
{public void createMultiInstances(){System.out.println(\n** MULTIPLE INSTANCES FROM SINGLETO **\n);/** Using Reflection you can break singleton*/try {Class clazz Class.forName(com.ddlab.rnd.patterns.SingletonType1);Constructor constructor clazz.getDeclaredConstructors()[0];constructor.setAccessible(true);SingletonType1 instance1 (SingletonType1)constructor.newInstance(null);SingletonType1 instance2 (SingletonType1)constructor.newInstance(null);SingletonType1 instance3 (SingletonType1)constructor.newInstance(null);System.out.printf( %-15s %-15s %n, SERIAL NO, MULTI INSTANCES);System.out.printf( %-15s %-15s %n, ---------, ---------------);System.out.format(%-15s %-15s %n, INSTANCE 1 ,instance1);System.out.format(%-15s %-15s %n, INSTANCE 2 ,instance2);System.out.format(%-15s %-15s %n, INSTANCE 3 ,instance3);}catch (Exception e) {e.printStackTrace();}}public void createMultiInstances1(){System.out.println(\n********* MULTIPLE INSTANCES FROM SINGLETON ********\n);/** Using Reflection you can break singleton*/try {Class clazz Class.forName(com.ddlab.rnd.patterns.SingletonType1);Method method clazz.getDeclaredMethods()[0];Field field clazz.getDeclaredFields()[0];field.setAccessible(true);SingletonType1 instance1 (SingletonType1)method.invoke(clazz, null);field.set(clazz, null);SingletonType1 instance2 (SingletonType1)method.invoke(clazz, null);field.set(clazz, null);SingletonType1 instance3 (SingletonType1)method.invoke(clazz, null);System.out.printf( %-15s %-15s %n, SERIAL NO, MULTI INSTANCES);System.out.printf( %-15s %-15s %n, ---------, ---------------);System.out.format(%-15s %-15s %n, INSTANCE 1 ,instance1);System.out.format(%-15s %-15s %n, INSTANCE 2 ,instance2);System.out.format(%-15s %-15s %n, INSTANCE 3 ,instance3);}catch (Exception e) {e.printStackTrace();}}public void createInstances(){System.out.println(\n*********** SINGLE INSTANCES FROM SINGLETON ********\n);SingletonType1 instance1 SingletonType1.getInstance();SingletonType1 instance2 SingletonType1.getInstance();SingletonType1 instance3 SingletonType1.getInstance();System.out.printf( %-15s %-15s %n, SERIAL NO, INSTANCES);System.out.printf( %-15s %-15s %n, ---------, ----------);System.out.format(%-15s %-15s %n, INSTANCE 1 ,instance1);System.out.format(%-15s %-15s %n, INSTANCE 2 ,instance2);System.out.format(%-15s %-15s %n, INSTANCE 3 ,instance3);}public static void main(String[] args) {new TestSingletonType1().createInstances();new TestSingletonType1().createMultiInstances();new TestSingletonType1().createMultiInstances1();}} 如果运行上述程序您将能够看到已定义的singleton类的许多实例。 但是我们知道可以使用反射来破坏Singleton的私有构造方法。 在上述情况下我们可以创建具有私有构造函数的类的实例也可以访问私有字段。 哦是的。。。您真的创建了多个实例吗是的BOSS我做了您觉得呢 您以任何方式构建设计但我可能会破坏。 确实这伤害了像我这样真正的情感开发者的情绪。 OKKkkk。 现在我将编写一个非常有效的代码这样您就不会崩溃。 真的是…….. ???????? 学习Java Relection机制对于探索JAVA的美丽至关重要。 现在让我们看看如何编写更好的代码以便其他开发人员将无法使用反射进行破坏。 package com.ddlab.rnd.patterns;
import java.lang.reflect.ReflectPermission;
import java.security.Permission;public class SingletonType2
{static{getInstance();}private static SingletonType2 instance null;private SingletonType2(){super();//Add the following piece of code so that it can not be invoked using relectionSystem.setSecurityManager(new SecurityManager() {Overridepublic void checkPermission(Permission perm) {if (perm instanceof ReflectPermission ){System.out.println(\nYes I will not allow you to create the instance using Reflection...\n);throw new SecurityException();}else{//Do nothing}}});}public static SingletonType2 getInstance(){if( instance null )instance new SingletonType2();return instance;}
} 现在确实如此您的反射攻击将不会影响上述代码。 如果使用反射创建另一个实例则将在此处获得Exception。 您可以考虑一下使用Java自省实用程序可能会破坏它。 您可能还认为我们将不会访问构造函数而是将访问该字段然后将字段值设置为null然后再次调用该字段。 这是一个很好的策略但是您会失败因为自省实用程序是另一种反映。 由于我们不允许反射因此您将无法创建多个实例。 但是您仍然可以使用自省来调用方法“ getInstance”但是您将获得相同的实例。 因此我们在这种情况下可以省去反思和反思的想法。 让我们以不同的方式思考指向类的序列化。 那么如果我们要序列化会发生什么呢 在上面的类中您不能继承因为构造函数是私有的对于防弹机制您可以将类定为最终类。 我们无法序列化SingletonType2类因为它没有实现Serializable接口并且我们也不允许反射。 但是我们无法序列化未实现Serilizable接口的类。 但是有时需要将Singleton对象保留一天。 在这种情况下我们必须在单例类中实现Serializable接口。 现在我们的项目或产品需要序列化并且我们将不使用SecurityManager概念。 让我们修改上面的类。 让我们看看带有Serializable接口的Singleton类。 package com.ddlab.rnd.patterns;
import java.io.Serializable;public class SingletonType11 implements Serializable
{private static final long serialVersionUID -4137189065490862968L;private static SingletonType11 instance null;private SingletonType11(){super();}public static SingletonType11 getInstance(){if( instance null )instance new SingletonType11();return instance;}
} 好的我们将能够序列化上面的类但是我们再次为黑客提供了创建多个实例的机会因此我们的概念再次在这里中断。 让我们看看如何通过对象序列化再次打破Singleton的概念。 让我们用这样编写一个小类。 package com.ddlab.rnd.patterns;
import java.io.Serializable;public class BreakSingleton implements Serializable
{private static final long serialVersionUID 5904306999023481976L;private SingletonType11 instance2 SingletonType11.getInstance();public SingletonType11 getInstance2() {return instance2;}public void setInstance1(SingletonType11 instance2) {this.instance2 instance2;}
} 让我们看看上面的测试工具类。 package com.ddlab.rnd.patterns;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;public class TestBreakSingleton
{public static void main(String[] args) throws Exception{BreakSingleton bs new BreakSingleton();OutputStream out new FileOutputStream(data/a.ser);ObjectOutputStream oout new ObjectOutputStream(out);oout.writeObject(bs);oout.flush();oout.close();out.flush();out.close();InputStream in new FileInputStream(data/a.ser);ObjectInputStream oin new ObjectInputStream(in);BreakSingleton bs1 (BreakSingleton)oin.readObject();oin.close();in.close();System.out.println(Instance from Serialization :::bs1.getInstance2());System.out.println(Normal Instance :::SingletonType11.getInstance());InputStream in1 new FileInputStream(data/a.ser);ObjectInputStream oin1 new ObjectInputStream(in1);BreakSingleton bs2 (BreakSingleton)oin1.readObject();oin1.close();in1.close();System.out.println(Another Instance from Serialization :::bs2.getInstance2());}} 如果运行上述程序则将获得以下类型的输出。 Instance from Serialization :::com.ddlab.rnd.patterns.SingletonType112586db54Normal Instance :::com.ddlab.rnd.patterns.SingletonType1112276af2Another Instance from Serialization :::com.ddlab.rnd.patterns.SingletonType1138a97b0b 因此现在您获得了Singleton类的三个不同实例。 同样我们遇到了多个实例的问题。 有什么办法可以使我们不会给黑客机会创建多个实例而是可以序列化该对象 哦是的有。 现在让我们看一下修改后的单例Java类以便能够序列化该对象并且在任何时间点都将获得一致的单例类。 package com.ddlab.rnd.patterns;
import java.io.ObjectStreamException;
import java.io.Serializable;public class SingletonType11 implements Serializable
{private static final long serialVersionUID -4137189065490862968L;private static SingletonType11 instance null;private SingletonType11(){super();}public static SingletonType11 getInstance(){if( instance null )instance new SingletonType11();return instance;}private Object readResolve() throws ObjectStreamException{return instance;}private Object writeReplace() throws ObjectStreamException{return instance;}
} 在上述方法中我们将从序列化对象和“ getInstance”方法的常规调用中获得一致的单例对象。 但是我们仍然可以使用Reflection创建多个实例并且由于要序列化对象而无法防止反射。 在这种情况下我们可以向开发人员提出请求并达成协议不要仅使用反射来避免反射策略。 开发人员达成了一项协议即不破坏使用反射。 那么多线程或在多线程应用程序中使用单例呢 让我们看看这里发生了什么。 让我们看看在Singleton类的情况下线程的使用。 让我们考虑一下我们前面讨论的第一个Singleton类。 package com.ddlab.rnd.patterns;
public class SingletonType1
{private static SingletonType1 instance null;private SingletonType1(){super();}public static SingletonType1 getInstance(){if( instance null )instance new SingletonType1();return instance;}
} 基本上这种方法称为延迟初始化。 在多线程的情况下如果处理不当我们可以获得多个实例。 让我们看下面的代码。 package com.ddlab.rnd.patterns;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;class Thread1 extends Thread
{Overridepublic void run() {SingletonType1 instance SingletonType1.getInstance();// System.out.println(In Thread 1 - Singleton Instance ----instance);TestSingletonType1_Thread.singletonSet.add(instance);}
}class Thread2 extends Thread
{Overridepublic void run() {SingletonType1 instance SingletonType1.getInstance();// System.out.println(In Thread 2 - Singleton Instance ----instance);TestSingletonType1_Thread.singletonSet.add(instance);}
} 让我们看看测试类如何使用它。 public class TestSingletonType1_Thread
{private static Set singletonSet1 new HashSet();public static Set singletonSet Collections.synchronizedSet(singletonSet1);public static void main(String[] args) {//Singleton concept is broken herefor( int i 0 ; i 100 ; i ){new Thread1().start();new Thread2().start();if( singletonSet.size() 1 )break;elsecontinue;}System.out.println(singletonSet);}
} 如果您多次运行上述程序则将获得Singleton类的不同实例。 运行该程序后您可能会得到类似的结果。 输出如下。 [com.ddlab.rnd.patterns.SingletonType160723d7c, com.ddlab.rnd.patterns.SingletonType16d9efb05, com.ddlab.rnd.patterns.SingletonType18dd20f6] 那么该怎么办 我们可以声明volatile变量现在让我们看看。 让我们拥有修改后的程序。 package com.ddlab.rnd.patterns;
public class SingletonType1
{private static volatile SingletonType1 instance null;private SingletonType1(){super();}public static SingletonType1 getInstance(){if( instance null )instance new SingletonType1();return instance;}
} 在多次运行该程序后您可能会得到这样的信息。 [com.ddlab.rnd.patterns.SingletonType13f0ef90c, com.ddlab.rnd.patterns.SingletonType12e471e30] 但是使用volatile不能满足我们的目的。 还是同样的问题我们可以使用同步方法吗是的我们可以做到。 在许多情况下大多数开发人员会提出与volatile关键字的用法及其在Singleton中的用法有关的问题。 如果经验不足的开发人员在其计算机上的第一次运行中获得上述类的单个实例则可能会感到高兴。 我有许多开发人员通过在其计算机上运行该程序来证明其合理性并且他们也向我展示了。 这是正确的因为他们很幸运。 但是我在他们的机器上多次运行了该程序并告诉他们不要忘记事实。 现在他们中的许多人开始使用java的great关键字和“同步的”生命保护程序来修改程序。 让我们看看这个关键字会发生什么。 让我们在下面看到。 package com.ddlab.rnd.patterns;
public class SingletonType1
{private static volatile SingletonType1 instance null;private SingletonType1(){super();}public static synchronized SingletonType1 getInstance(){if( instance null )instance new SingletonType1();return instance;}
} 但是会出现性能问题。 但是当您对其进行分析时您将意识到仅在第一次调用该方法时才需要同步。 后续调用不需要同步。 因此不建议在每次调用时都使用关键字“ synchronized”。 从长远来看它可能会对您的产品/项目开发产生不利影响。 为了提高上述程序的效率请使用以其他方式修改上述程序。 我们不会同步整个方法而是会做敏感区域。 package com.ddlab.rnd.patterns;
public class SingletonType1
{private static volatile SingletonType1 instance null;private SingletonType1(){super();}public static SingletonType1 getInstance(){if (instance null){synchronized(SingletonType1.class) {instance new SingletonType1();}}return instance;}
} 上面的程序看起来还不错我们很高兴现在让我们庆祝。 但是由于存在一个很大的问题我们仍然远离艰苦的现实。 当instance为null时两个线程可以同时进入if语句内部。 然后一个线程进入同步块以初始化实例而另一个则被阻塞。 当第一个线程退出同步块时等待线程进入并创建另一个Singleton对象。 请注意当第二个线程进入同步块时它不会检查实例是否为非空。 让我们做一个小的临床测试来面对现实。 package com.ddlab.rnd.patterns;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;class Thread11 extends Thread
{Overridepublic void run() {SingletonType111 instance SingletonType111.getInstance();// System.out.println(In Thread 1 - Singleton Instance ----instance);TestSingletonType111_Thread.singletonSet.add(instance);}
}class Thread22 extends Thread
{Overridepublic void run() {SingletonType111 instance SingletonType111.getInstance();// System.out.println(In Thread 2 - Singleton Instance ----instance);TestSingletonType111_Thread.singletonSet.add(instance);}
}public class TestSingletonType111_Thread
{private static Set singletonSet1 new HashSet();public static Set singletonSet Collections.synchronizedSet(singletonSet1);public static void main(String[] args) {//Singleton concept is broken herefor( int i 0 ; i 100 ; i ){new Thread11().start();new Thread22().start();if( singletonSet.size() 1 )break;elsecontinue;}System.out.println(singletonSet);}} 现在您将多次了解上述程序。 接下来要做什么。 现在让我们考虑另一个被称为“双重检查锁定”的概念该概念对于一组开发人员而言似乎是著名的。 许多开发人员在许多情况下都适用并认为这是最强大的单例形式。 在软件工程中双重检查锁定也称为“双重检查锁定优化”是一种软件设计模式用于通过先测试锁定条件“锁定提示”而无需实际获取锁定来减少获取锁定的开销。锁。 只有在锁定 标准检查表明是否需要锁定实际的锁定逻辑是否继续进行。 在大多数技术面试中技术小组都希望候选人能给出这个答案。 如果候选人能够根据自己的喜好回答此问题技术小组将很高兴并选择候选人。 如今它的概念已经变得非常重要但是我要说的是技术小组对此概念没有足够的经验。 让我们对其进行非常深入的分析。 “双重检查锁定”的基本结构如下。 public static SingletonType1 getInstance()
{if (instance null){synchronized(SingletonType1.class) // Mark - 1{ if (instance null) // Mark - 2instance new SingletonType1(); // Mark - 3}}return instance;
} 双重检查锁定背后的理论是// // Mark – 2处的第二次检查使不可能创建两个不同的Singleton对象。 好的... 对于单线程应用程序可能是正确的。 细粒度的多线程应用程序呢 让我们看下面的顺序。 线程1进入getInstance方法。 线程1在// Mark – 1处进入同步块因为实例为空。 线程1被线程2抢占。 线程2进入getInstance方法。 线程2尝试获取// Mark – 1处的锁因为实例仍然为空。 但是由于线程1持有该锁因此线程2在// Mark – 1处阻塞。 线程2被线程1抢占。 执行线程1并且由于在// Mark – 2处instance仍然为null因此创建了Singleton对象并将其引用分配给实例。 线程1退出同步块并从getInstance方法返回实例。 线程1被线程2抢占。 线程2获取// // Mark – 1处的锁并检查instance是否为null。 由于instance非null因此不会创建第二个Singleton对象并且将返回线程1创建的对象。 双重检查锁定背后的理论是完美的。 不幸的是现实是完全不同的。 双重检查锁定的问题在于不能保证它可以在单处理器或多处理器计算机上工作。 双重检查锁定失败的问题不是由于JVM中的实现错误而是由于当前的Java平台内存模型。 内存模型允许所谓的“乱序写入”这是该成语失败的主要原因。 但是“乱序写入”的概念超出了我们的讨论范围。 最重要的是不应以任何形式使用经过仔细检查的锁定因为您不能保证它可以在任何JVM实现上使用。 如我们所见虽然“双重检查锁定”可能有效但可能会意外失败。 解决办法是什么 Bill Pugh的解决方案 马里兰大学计算机科学研究员Bill Pugh摘自Wikipedia撰写了有关用Java实现Singleton模式的代码问题。 Pugh对“双重检查锁定”这一习惯用法的努力导致了Java 5中Java内存模型的变化并导致了通常被视为在Java中实现Singletons的标准方法。 这种技术称为按需初始化持有人惯用语它尽可能懒惰并且可以在Java的所有已知版本中使用。 它利用了有关类初始化的语言保证因此可以在所有Java兼容的编译器和虚拟机中正常工作。 嵌套类的引用不早于调用getInstance的时间因此类加载器不会更早地对其进行加载。 因此该解决方案是线程安全的不需要特殊的语言构造即易失性或同步的。 public class Singleton
{// Private constructor prevents instantiation from other classesprivate Singleton() { }/*** SingletonHolder is loaded on the first execution of Singleton.getInstance() * or the first access to SingletonHolder.INSTANCE, not before.*/private static class SingletonHolder { public static final Singleton INSTANCE new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
} 上面称为“ 按需初始化持有人习惯用法 ”。 Singleton设计的上述结构在高度多线程的应用程序中非常强大。 让我们详细了解这个概念。 让我们考虑一个下面的小例子。 public class Something
{private Something() {}private static class LazyHolder{public static final Something INSTANCE new Something();}public static Something getInstance() {return LazyHolder.INSTANCE;}
} 这个怎么运作 该实现依赖于Java虚拟机JVM中执行良好的初始化阶段。 有关详细信息请参见Java语言规范JLS的12.4节。 当JVM加载Something类时该类将进行初始化。 由于该类没有任何静态变量可初始化因此初始化很容易完成。 在JVM确定必须执行LazyHolder之前不会初始化其中的静态类定义LazyHolder。 静态类LazyHolder仅在对Something类调用静态方法getInstance时执行并且第一次发生这种情况时JVM将加载并初始化LazyHolder类。 LazyHolder类的初始化导致静态变量INSTANCE的执行是通过对外部类Something执行私有构造函数来进行的。 由于JLS保证类的初始化阶段是串行的即非并发的因此在加载和初始化期间静态getInstance方法中不需要进一步的同步。 并且由于初始化阶段在串行操作中写入了静态变量INSTANCE因此对getInstance的所有后续并发调用将返回相同的正确初始化的INSTANCE而不会产生任何其他同步开销。 但是使用“按需初始化持有人惯用语”模式的概念我们可以实现线程安全的单例构造。 再次出现问题我们可以反思地打破吗。 是的我们可以使用我已经提到的java反射机制打破上述概念。 现在问题来了是否还有其他方法可以构建适当的单例设计方法。 是的 Joshua BlochGoogle技术实验室首席技术架构师和著名的Book Effective Java的作者建议使用另一种方法。 package com.ddlab.rnd.patterns;
public enum SingletonType3
{INSTANCE;public void doSomething(String arg) {//... perform operation here ...}
} 这是创建单例类的唯一可靠方法该类是可序列化的并且在默认情况下是完全线程安全的而枚举是完全线程安全的。 关于反射使用上面的反射方法您不能破坏单例对象因为它没有构造函数。 关于序列化您将能够对其进行序列化但是每次都会获得相同的实例。 因此最后我们必须吸收这种创建Singleton设计类的现代方法。 但是许多开发人员对此一无所知。 但是大多数访调员不会接受以上两种方法因为对他们而言这可能是一个新概念。 您可以根据JLS和参考书进行论证。 我的大三同事和朋友每天都抱怨在面试时这是他们通常在面试时面临的最困难的问题。 无论他们以何种方式回答问题面试官都不会满意这是因为大多数人不了解单例设计课程中的枚举方法。 如果您也遇到同样的问题请以约书亚·布洛赫Joshua Bloch为例。 您可能会遇到一些开发人员或访问员的问题即“ Singleton类必须具有私有构造函数并且应该有一个名为getInstance的方法”。 您必须论证说下划线语句是错误的而不是协议或任何经验法则。 这只是我们一段时间以来采用的一种方法。 单例背后的主要概念是在任何时间点都应该只有一个实例与如何编写代码无关。 如果面试不断地与您争论您会问他将枚举定义为单例方法的问题所在。 胆小的面试官可能会提出一些无稽之谈。 最后您告诉他在JDK 5中枚举由Josh Bloch和Neal Gafter编写。 如果开发人员或面试官有胆量他可以将邮件发送给这些优秀的建筑师。 如果傲慢的面试官仍在作出错误的论点请教给他一个教训“先生您告诉我单身人士的做法这是无法打破的。 至少我会以各种方式破坏您的Singleton设计。” 仍然不能使用枚举破坏上述单例方法但是我们可以通过编写代码来创建多个实例来破解上述方法。 下面给出的代码请勿将以下代码用于您的商业产品。 这是打破单例的讨厌方法。 让我们看下面的代码。 package com.ddlab.rnd.patterns;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import sun.reflect.ConstructorAccessor;public class CrackEnumSingleton
{public static void main(String[] args){Set set new HashSet();try {SingletonType3 firstInstance SingletonType3.INSTANCE;System.out.println(firstInstance.getClass() firstInstance System.identityHashCode(firstInstance));set.add(firstInstance);Constructor constructor SingletonType3.class.getDeclaredConstructors()[0];Method acquire constructor.getClass().getDeclaredMethod(acquireConstructorAccessor);//acquireConstructorAccessor fields for crackingacquire.setAccessible(true);acquire.invoke(constructor);Method get constructor.getClass().getDeclaredMethod(getConstructorAccessor);//getConstructorAccessor fields for crackingget.setAccessible(true);ConstructorAccessor invoke (ConstructorAccessor) get.invoke(constructor);Object secondInstance invoke.newInstance(new Object[] {null,1});System.out.println(secondInstance.getClass() secondInstance System.identityHashCode(secondInstance));set.add(secondInstance);System.out.println(Total No of Singletons :::set.size());}catch (Exception e) {e.printStackTrace();}}} 但是上述方法只是一种学习技术而并非在任何地方实现。 在这个世界上每个对象都有积极和消极的态度但是我们必须遵循积极的态度才能顺利开发我们的产品或项目。 结论 本文没有任何商业意义。 在本文中我提供了编写更好的Singleton设计类的更好方法。 可能有最佳方法如果您知道其他最佳方法或最佳做法请与我分享。 还提供一些注释以便我们可以为更好的编码标准做出更好的贡献。 希望您喜欢我的文章。 如有任何错误请通过debadatta.mishragmail.com向我报告。 谢谢。 参考 Singleton设计模式– Debadatta Mishra博客上来自JCG合作伙伴 Debadatta Mishra的鸟瞰图 。 翻译自: https://www.javacodegeeks.com/2013/06/singleton-design-pattern-a-lions-eye-view.html透视变换–鸟瞰图