Java:getInstance和Static的区别

34

getInstance()在Java中的作用是什么?

在我的研究中,我一直在阅读getInstance()可以帮助实现单例设计模式(也就是整个程序只有一个实例),但是我不能使用静态方法吗?这不是静态的全部意义吗?

如果我只使用静态方法和变量,它将与使用getInstance()有什么区别?静态的“范围”是否存在?例如,每个方法或类都有一个实例吗?

如果它们是不同的,请问在什么情况下会选择getInstance()而不是使用静态方法?

如果我的问题不太清楚,我很抱歉,我确信自己在这个主题上缺少一些东西,但我无法确定是什么。

感谢您提供的所有建议。


在JAVA中没有“每个方法一个实例”的概念。 - Braj
1
getInstance() 可以是一个 static 方法... - awksp
2
对于单例模式,getInstance是一个静态方法,并使用静态属性。 - Guj Mil
1
静态变量的整个目的是将事物与而不是特定的对象相关联。单例模式保证您将拥有该类型的一个对象实例。 - azurefrog
1
@Braj 感谢您的评论,我没有意识到getInstance的目的是充当访问器。 - FreakyDan
显示剩余5条评论
6个回答

22

静态关键字不会使您获得单例模式。由于在Java中没有办法使顶级类成为单例,因此您可以使用getInstance方法来实现某些逻辑以确保只有一个类的实例存在。

public class Singleton {

   private static Singleton singleton;

   private Singleton(){ }

   public static synchronized Singleton getInstance( ) {
      if (singleton == null)
          singleton=new Singleton();
      return singleton;
   }

}

请查看这个最佳答案:Java中的静态类

以上代码将只允许创建一个实例,而且很干净,但是从Java 1.6开始,我认为更优雅的做法是这样创建单例:

public enum MyEnumSingleton {
    INSTANCE;

    // other useful methods here
} 

来源: http://www.vogella.com/tutorials/DesignPatternSingleton/article.html


非常感谢您的解释。我最初认为getInstance Java方法是内置的,而不是访问器方法。 - FreakyDan
你的getInstance()实现不适合单例模式。 - Bohemian
啊,你说得完全正确 :) 我从来没有设置我的实例。我很匆忙离开工作。好发现! - Zac Lozano
好了!再次感谢@Bohemian。 - Zac Lozano
1
这不是我想说的。你的方法不是线程安全的,因此即使修复了字段设置,仍然可能创建多个类的实例。 - Bohemian
你展示了如何创建单例,但这并没有回答问题。问题是静态模式和单例模式之间的区别以及一个优于另一个的好处。 - Gleb Varenov

11

单例模式

单例模式允许您使用一个Java对象的单个引用。举个例子,下面是一个包含数字的单例模式:

public class MySingleton {

    private int myNumber;
    private static MySingleton instance;

    public static MySingleton getInstance() {
        if (instance == null) {
             instance = new MySingleton();
        }
        return instance;
    }

    private MySingleton() {}

    public void setMyNumber(int myNumber) {
        this.myNumber = myNumber;
    }

    public int getMyNumber() {
       return myNumber;
    }
}

现在我们将在A类中设置这个数字的值:

public class A {
    /*...*/
    MySingleton mySingleton = MySingleton.getInstance();
    mySingleton.setMyNumber(42);
    /*...*/
}

然后,您可以从另一个类中访问此值:

public class B {
    /*...*/
    MySingleton mySingleton = MySingleton.getInstance();
    int number = mySingleton.getMyNumber();
    /*...*/
}

在这个类中,number变量的值将为42。这是单例模式优于简单对象的优点:

存储在单例中的所有值将可以从“任何地方”访问。


静态类

其目的不同,在这里,优点是可以使用对象而无需创建它。

例如:

public static class MyStaticClass {
    public static void sayHello() {
        System.out.println("Hello");
    }
}

现在您可以通过调用以下方式,在任何类中使用sayHello()方法:

MyStaticClass.sayHello(); 

1
你实际上可以使用任何类来实现这种行为(即,无论类是否标记为静态,静态方法始终使用类名调用)。内部静态类的主要优点是它不附加到任何外部Outer类实例。 - Zac Lozano

3

实现单例模式的确切方法,例如使用名为getInstance() 的工厂方法,对于问题并不那么重要,问题是“静态方法vs具有实例方法的单例模式”。

类本身就是有效的单例,因此从这个方面来看它们是相似的。

主要区别在于静态方法不是类继承体系的一部分 - 它们不会被继承,这意味着静态方法选项将永远锁定您使用精确的类,并且无法以其他方式引用它,如某些接口的实现或超类。

然而,实例没有这个问题,因此您可以编写例如:

class MySingleton implements SomeInterface {
    ...
}

SomeInterface instance = MySingleton.getInstance();

1

与其检查 null,我更喜欢这种方式。

public class SingleObject {

    //create an object of SingleObject
    private static SingleObject instance = new SingleObject();

    //make the constructor private so that this class cannot be
    //instantiated
    private SingleObject(){}

    //Get the only object available
    public static SingleObject getInstance(){
        return instance;
    }
}

被调用时使用...

public class SingletonPatternDemo {
   public static void main(String[] args) {

      //illegal construct
      //Compile Time Error: The constructor SingleObject() is not visible
      //SingleObject object = new SingleObject();

      //Get the only object available
      SingleObject object = SingleObject.getInstance();
   }
}

完整代码来自:http://www.tutorialspoint.com/design_pattern/singleton_pattern.htm


1
我更喜欢使用 static,但有时候 getInstance() 很有用,可以让一些函数与对象相关联,在其中修改变量。如果你只是编写一些不需要对象实例的实用函数,请使用 static
当你使用别人的库时,你永远不知道一个函数体是否需要一个类实例。这就是为什么很多库类使用 getInstance() 的原因。

1
一个被忽视的使用单例而非静态类成员变量的原因是即使类从未实例化,静态成员变量也可能会占用空间和垃圾回收时间。考虑一下在rt.jar中提供给您的类数量以及在任何给定应用程序中您可能只使用其中的一小部分。此外,请考虑使用getInstance可以确保在访问任何成员变量之前运行您的“构造函数”。我几乎总是看到getInstance被同步,但我认为这是一个不好的想法。如果有人将同步阻塞方法调用添加到Singleton.getInstance()中,则可能需要无谓地等待。
private static Singleton instance = null;
private Singleton() {}
public final static Singleton getInstance() {
    return (instance != null) ? instance : makeInstance();
}
private final static synchronized Singleton makeInstance() {
    return ( instance != null ) ? instance : ( instance = new Singleton() );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接