如何在 Java 中制作单例? 初始化类型、比较和要记住的要点
已发表: 2020-10-07Java 中的单例类被定义为只有一个对象的类,即只有一个类的实例。 将实例限制为每个类只有一个有助于编写只需要一个类实例的特定程序。 单例类的唯一实例被赋予一个全局访问点。
单例类是 Java 编程中重要的设计模式之一。 单例类有助于限制资源和优化资源; 它在数据库连接或套接字中被大量使用。 单例类有实现语法,优秀的开发者必须知道。 让我们看看 Java 中单例类的实现。
从世界顶级大学在线学习软件工程师课程。 获得行政 PG 课程、高级证书课程或硕士课程,以加快您的职业生涯。
阅读: Java 架构和组件解释
目录
初始化
Java 中单例的初始化是通过私有构造函数完成的。 私有构造函数有助于其他类无法创建与单例类相同的实例。 Java中有五种类型的单例类初始化,如下所示:
1.渴望初始化
创建了一个通常命名为 getInstance() 的公共方法。 此方法将有助于只为创建类的实例提供一个入口点,从而使其成为单例类。 急切初始化中的类实例是在类加载时创建的。

这种类型的初始化技术会自动创建类的实例,即使用户没有使用它。 这可能会导致内存问题和代码中不必要的长度。 为了解决内存泄漏问题,让我们看看另一种类型的 Java 中单例类的初始化技术。
2. 延迟初始化
类的实例在方法 getInstance () 本身中以延迟初始化的方式初始化。 惰性初始化中的方法会检查类的实例是否被创建,如果没有创建,则只创建一个实例,从而解决内存泄漏问题。
在延迟初始化中创建的方法是静态的并且具有返回类型对象。 在第一次调用 getInstance() 方法之前,不会创建延迟初始化中的单例实例。
3. 使用双锁方法进行延迟初始化
此方法在多个线程时使用。 如果我们在程序中使用了两个线程,并且在实例为空的情况下启动时都可以通过'if'语句访问它们,则会产生冲突的情况,您可能会发现错误。
这个问题通过双锁方法解决了,在这种方法中,一次只有一个线程进入同步块中以初始化实例,而另一个线程被阻塞。 当第一个线程退出同步块时,只有第二个线程进入并创建另一个实例。 默认情况下,第二个线程不检查实例是否为非空。
4. 延迟加载方法
嵌套内部类是在此方法中创建的,并按照 JLS(Java 语言规范)的原则工作。 类中没有静态数据成员; JVM 不会创建该类的实例。 只有当我们调用 getInstance() 方法时,才会按需创建实例。

您不需要同步初始化和加载方法,因为此方法有助于自动同步所有获取 Instance() 的调用。
5.枚举方法
在上述方法中,仍然可以通过序列化和反射创建单例类的多个实例。 在制作严格的单例类的情况下,可以使用这种方法。 此方法中使用枚举字段,它是一个常量,仅在编译时运行。
Enum 是 Enum 类型的实例,只有在代码中第一次调用/调用 Enum 类型时才会构造。 该方法限制了实例的克隆,并制作了一个完美的单例类。
另请阅读:您今天应该检查的 12 大 Java 模式程序
序列化和反射
序列化有助于将 Java 对象从一个 JVM(Java 虚拟机)传输到另一个。 序列化是用于创建类的多个实例的方法之一。 序列化将对象转换为字节流,然后传输完成。
字节流有助于使用反序列化过程在其他一些 JVM 中重新创建对象。 它帮助多个系统在它们之间进行通信和共享对象。 它有助于跨 JVM 同步,因为对象将在不同的 JVM 中工作。
反射也是Java中克隆对象的一种方法。 反射是一个 API,它可以帮助我们了解任何未知对象的类和可以通过对象访问的特定类的方法。 反射被程序员广泛用于在运行时修改类和方法的行为。
反射中用到的三个主要命令是getClass()知道对象所属的类,getConstructors()得到对象所属类的公共构造函数,getMethods()知道被观察类的公共方法。
普通班与单身班
Java 中的标准类使用构造函数来初始化自身,而我们使用 getInstance() 方法来初始化单例类。 我们也可以使用相同的类和方法名。 我们首先为普通类创建一个对象,然后我们使用它的方法和属性。
相反,在单例类中,我们使用类的静态属性创建一个实例,并且在整个代码中的任何时候,该特定类都将只返回一个实例。
除了单例类的许多优点之外,如果对象和方法紧密耦合,也存在一些漏洞,例如单例类篡改单元测试方法。 在这种情况下,您必须将一个功能齐全的类专用于单例。
隐藏的依赖项有时也由单例类创建,因为单例类的引用被传递给其他方法并且它不是完全透明的,因此编码人员/开发人员很难跟踪方法和类。 在创建单例模式之前,应牢记这些缺点,并应尽量减少它。
制作完美单例类的要点
1. 做一个完美的单例类应该关注的点如下:
2. 如果你在一个单例类中创建多个线程,那么确保所有线程不应该同时初始化单例类。 应该尝试制作线程安全的单例类。

3. 通过在运行时更改构造函数对公众的可见性并确保任何特定的单例类只有一个实例,使您的单例类反射证明。
4. 如果有多个线程,可以使用 volatile 修饰符,防止一个线程查看其他线程的初始化状态。 volatile 修饰符作用于happens-before 关系,其中写入发生在线程中,然后任何其他线程可以读取它。
必读:适合初学者的有趣 Java 项目创意
结论
单例类用于与数据库或您想要控制类的方法和实例的任何程序建立自定义连接。
如果您想提高您的 Java 技能,您需要掌握这些 Java 项目。 如果您有兴趣了解有关 Java、全栈开发的更多信息,请查看 upGrad 和 IIIT-B 的软件开发执行 PG 计划 - 全栈开发专业化,该计划专为工作专业人士设计,提供 500 多个小时的严格培训,9 + 项目和任务、IIIT-B 校友身份、实用的实践顶点项目和顶级公司的工作协助。
