HOWTO · Java

Java 单例类

本教程介绍 Java 单例类。它还演示了为什么它很重要,如何使用不同的设计模式编写 Java 单例类。

本页内容

本教程将在定义级别讨论单例类并强调其重要性。我们将描述编写 Java 单例类的各种设计模式,并借助代码示例对其进行解释。

Java 中的单例类

Java 单例类允许我们一次只创建该类的一个实例,该实例通过这个单一实例(也称为类的对象)全局服务于所有类。单例类不同于用于特定目的的普通类。

它包括避免类的不必要的实例化并确保一次只存在一个对象。它可以节省内存并加快工作速度。

请参阅下面的代码,其中我们有 ABC 和 XYZ 类。ABC 类有一个名为 method1 的方法,它打印字符串 "Hi"。

我们在 XYZ 类中创建类 ABC 的实例来调用驻留在类 ABC 中的 method1,我们创建另一个名为 ABC 的实例并再次调用 method1 以在下面打印"Hi" XYZ 类。现在,我们有两个名为 object1 和 object2 的实例(对象),它们拥有不同的引用,但调用同一类的相同函数。

我们创建了类 ABC 的两个对象,它们是类的不必要实例化。我们可以对单个对象做同样的工作。

其次,每当我们创建一个对象时,它都会占用内存中的空间,这意味着我们通过创建同一个类的多个对象来浪费内存。这就是我们使用单例类来避免这些情况的地方。

示例代码:

public class ABC {
  // constructor
  public ABC() {}
  // method1
  public void method1() {
    System.out.println("Hi");
  }
}

public class XYZ {
  // first instance of ABC class
  ABC object1 = new ABC();
  object1.method1();

  // second instance of ABC class
  ABC object2 = new ABC();
  object2.method1();
}

单例类在各种应用程序中非常有用,包括日志记录、线程池、配置设置、缓存、数据库应用程序等。

在 Java 中使用各种方法使用单例类

在 Java 编程中编写单例类有多种方法,计算机程序员可以从中选择。但是所有方法都属于以下单例类的任何一种设计模式。

  1. 延迟初始化
  2. 早期初始化

对于我们在编写单例类时使用的任何方法,都应考虑以下因素。

  1. 类的构造函数必须是 private。
  2. 单例类必须有一个静态方法来返回这个(单例)类实例。

使用延迟初始化方法的 Java 单例类

示例代码(Singleton.java):

class Singleton {
  private static Singleton object = null;
  public String message;

  private Singleton() {
    message = "Hi I live in the Singleton class";
  }

  public static Singleton getInstance() {
    if (object == null)
      object = new Singleton();

    return object;
  }
}

示例代码(Test.java):

public class Test {
  public static void main(String args[]) {
    Singleton obj1 = Singleton.getInstance();
    Singleton obj2 = Singleton.getInstance();
    Singleton obj3 = Singleton.getInstance();

    System.out.println("Hashcode of obj1 is " + obj1.hashCode());
    System.out.println("Hashcode of obj2 is " + obj2.hashCode());
    System.out.println("Hashcode of obj3 is " + obj3.hashCode());

    if (obj1 == obj2 && obj2 == obj3) {
      System.out.println("Three instances reference to the same memory location");
    } else {
      System.out.println("All are not referencing to the same memory location");
    }
  }
}

输出:

Hashcode of obj1 is 1490180672
Hashcode of obj2 is 1490180672
Hashcode of obj3 is 1490180672
Three instances reference to the same memory location

在此方法中,仅在需要时创建类对象。使用这种方法,我们可以避免对 Singleton.java 类进行不必要的实例化。

在 Singleton.java 类中,我们创建了该类的 private static 对象(实例),但不对其进行初始化。然后,我们编写一个 private 构造函数,确保没有其他类可以调用其默认构造函数(public)来创建对象。

最后,我们编写了一个 static 方法来检查 Singleton.java 类的实例,如果它是 null,它只创建这个类的实例。在 Test.java 类中,我们可以通过创建不同的对象来确认,以确保每次只创建和调用一个实例。

使用早期初始化方法的 Java 单例类

示例代码(Singleton.java):

class Singleton {
  private static final Singleton object = new Singleton();
  public String message;

  private Singleton() {
    message = "Hi I live in the Singleton class";
  }

  public static Singleton getInstance() {
    return object;
  }
}

示例代码(Test.java):

public class Test {
  public static void main(String args[]) {
    Singleton obj1 = Singleton.getInstance();
    Singleton obj2 = Singleton.getInstance();
    Singleton obj3 = Singleton.getInstance();

    System.out.println("Hashcode of obj1 is " + obj1.hashCode());
    System.out.println("Hashcode of obj2 is " + obj2.hashCode());
    System.out.println("Hashcode of obj3 is " + obj3.hashCode());

    if (obj1 == obj2 && obj2 == obj3) {
      System.out.println("Three instances reference to the same memory location");
    } else {
      System.out.println("All are not referencing to the same memory location");
    }
  }
}

输出:

Hashcode of obj1 is 1490180672
Hashcode of obj2 is 1490180672
Hashcode of obj3 is 1490180672
Three instances reference to the same memory location

在 Singleton.java 类中,我们创建该类的 private static final 实例并对其进行初始化。然后,我们编写一个 private 构造函数和一个静态方法来返回这个类的实例。

请记住,Signleton.java 类实例将在加载时创建。我们还可以将类的实例设置为 public static final 而不是 private static final,以直接访问该类。

此外,我们有相同的 Test.java 类,它打印并确保每次只调用一个实例。