静态类和单例模式之间存在什么实际的区别?

两者都可以在没有实例化的情况下调用,两者都只提供一个“实例”,而且都不是线程安全的。还有其他区别吗?


当前回答

与静态类相比,Singleton模式有几个优点。首先,单例可以扩展类和实现接口,而静态类不能(它可以扩展类,但不继承它们的实例成员)。单例可以延迟或异步初始化,而静态类通常在首次加载时初始化,这会导致潜在的类加载器问题。然而,最重要的优点是,可以在不强迫用户假设只有一个实例的情况下以多态的方式处理单态。

其他回答

这是一篇好文章:http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

静态类

具有所有静态方法的类。更好的性能(静态方法在编译时绑定)无法重写方法,但可以使用方法隐藏。(Java中隐藏的方法是什么?甚至JavaDoc的解释都令人困惑)公共级动物{公共静态void foo(){System.out.println(“动物”);}}公共课猫延伸动物{public static void foo(){//隐藏Animal.foo()System.out.println(“类别”);}}

辛格尔顿

只能实例化一次的对象。方法可以被重写(为什么Java不允许重写静态方法?)比静态方法更容易模拟更善于保持状态

总之,我只使用静态类来保存util方法,而使用Singleton来处理其他所有事情。


编辑

静态类也被延迟加载。谢谢@jmoreno(静态类初始化何时发生?)静态类的方法隐藏。谢谢@MaxPeng。

我将努力超越WTMI和WTL;DR响应。

单身者是一个物体的实例。。。句点

你的问题基本上是问类和该类的实例之间的区别。我认为这很清楚,不需要详细说明。

singleton的类通常采取步骤来确保构建一个实例;这很聪明,但不是必须的。

示例:var connection=connection.Instance;

假设这是Connection类:

public sealed class Connection 
{
    static readonly Connection _instance = new Connection();

    private Connection() 
    {
    }

    public static Connection Instance
    {
        get
        {
           return _instance;
        }
    } 
}

请注意,您可以在该类上抛出一个接口并模拟它以进行测试,这是静态类无法轻易做到的。

静态类是一个只有静态方法的类,对于这个类,更好的词是“函数”。静态类中体现的设计风格纯粹是过程性的。

另一方面,Singleton是OO设计特有的模式。它是一个对象的实例(具有其中固有的所有可能性,例如多态性),具有一个创建过程,确保在整个生命周期中只有一个特定角色的实例。

从测试角度来看,Singleton是更好的方法。与静态类不同,singleton可以实现接口,您可以使用mock实例并注入它们。

在下面的示例中,我将对此进行说明。假设您有一个使用getPrice()方法的方法isGoodPrice(。

提供getPrice功能的singleton:

public class SupportedVersionSingelton {

    private static ICalculator instance = null;

    private SupportedVersionSingelton(){

    }

    public static ICalculator getInstance(){
        if(instance == null){
            instance = new SupportedVersionSingelton();
        }

        return instance;
    }

    @Override
    public int getPrice() {
        // calculate price logic here
        return 0;
    }
}

getPrice的使用:

public class Advisor {

    public boolean isGoodDeal(){

        boolean isGoodDeal = false;
        ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
        int price = supportedVersion.getPrice();

        // logic to determine if price is a good deal.
        if(price < 5){
            isGoodDeal = true;
        }

        return isGoodDeal;
    }
}


In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it. 



  public interface ICalculator {
        int getPrice();
    }

最终Singleton实施:

public class SupportedVersionSingelton implements ICalculator {

    private static ICalculator instance = null;

    private SupportedVersionSingelton(){

    }

    public static ICalculator getInstance(){
        if(instance == null){
            instance = new SupportedVersionSingelton();
        }

        return instance;
    }

    @Override
    public int getPrice() {
        return 0;
    }

    // for testing purpose
    public static void setInstance(ICalculator mockObject){
        if(instance != null ){
instance = mockObject;
    }

测试等级:

public class TestCalculation {

    class SupportedVersionDouble implements ICalculator{
        @Override
        public int getPrice() { 
            return 1;
        }   
    }
    @Before
    public void setUp() throws Exception {
        ICalculator supportedVersionDouble = new SupportedVersionDouble();
        SupportedVersionSingelton.setInstance(supportedVersionDouble);

    }

    @Test
    public void test() {
          Advisor advidor = new Advisor();
          boolean isGoodDeal = advidor.isGoodDeal();
          Assert.assertEquals(isGoodDeal, true);

    }

}

如果我们选择使用静态方法来实现getPrice(),那么很难模拟getPrice)。您可以使用power mock模拟静态,但并非所有产品都可以使用它。

静态类示例

public class Any {

    private static Any instance = new Any();

    private Singleton() {
        System.out.println("creating");
    }
}

单例模式只存在一个实例:

public class Singleton {

    private static Singleton instance = new Singleton();

    private Singleton() {
        System.out.println("creating");
        if (instance != null) {
            throw new RuntimeException("Imposible create a new instance ");
        }
    }
}