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

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


当前回答

静态类通常用于库,如果我只需要特定类的一个实例,则使用单实例。但是,从内存的角度来看,存在一些差异:通常在堆中只分配对象,分配的唯一方法是当前正在运行的方法。静态类的所有方法都是静态的,从一开始就在堆中,所以通常静态类会消耗更多的内存。

其他回答

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

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

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

静态类通常用于库,如果我只需要特定类的一个实例,则使用单实例。但是,从内存的角度来看,存在一些差异:通常在堆中只分配对象,分配的唯一方法是当前正在运行的方法。静态类的所有方法都是静态的,从一开始就在堆中,所以通常静态类会消耗更多的内存。

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

问题是错误的,这两种说法都是错误的。请注意:这里的静态类意味着嵌套的静态类,而不是只有静态方法的类。

我假设(即,静态类意味着嵌套的静态类,而不是只有静态成员的类),因为如果我看到最流行的Singleton实现,即DCL方式,它只不过是实例的静态声明和获取Singleton实例的静态方法。它是一个实现。那么在这种情况下,Singleton和只有静态成员的类之间有什么区别呢。尽管其他实现也是可能的,比如使用Enum。

让我纠正以下说法:

Singleton类可以具有单实例应用程序范围。嵌套的静态类可以有多个实例(请参阅下面的代码作为证明)。在这里阅读嵌套类的基础知识。没有一个类本质上是线程安全的,它必须通过编程实现线程安全。它既可以用于嵌套静态类,也可以用于Singleton。

下面是更多的神话故事(这个问题的大多数答案都给出了这些陈述,因此认为最好通过编程来证明这一点):

嵌套的静态类可以像任何其他类一样实现接口。嵌套的静态类可以扩展其他非最终类。嵌套静态类可以具有实例变量。嵌套静态类可以具有参数化构造函数。

在下面的代码中,您可以看到嵌套的静态类NestedStaticClass实现了接口,扩展了另一个类,具有实例变量和参数化构造函数。

 package com.demo.core;

    public class NestedStaticClassTest
    {
        public static void main(String[] args)
        {
            OuterClass.NestedStaticClass obj1 = new OuterClass.NestedStaticClass();
            OuterClass.NestedStaticClass obj2 = new OuterClass.NestedStaticClass();

            if(obj1 == obj2)
            {
                System.out.println("Both nested static objects are equal....");
            }
            else
            {
                System.out.println("NOT EQUAL......");
            }

            System.out.println(OuterClass.NestedStaticClass.d);

            obj1.setD(5);

            System.out.println(OuterClass.NestedStaticClass.d);

            System.out.println(obj1.sum());
        }
    }

    class OuterClass
    {
        int a =1;
        static int b = 2;

        static class NestedStaticClass extends OneClass implements Sample
        {
            int c = 3;
            static int d = 4;

            public NestedStaticClass()
            {
            }

            //Parameterized constructor
            public NestedStaticClass(int z)
            {
                c = z;
            }

            public int sum()
            {
                int sum = 0;
                sum = b + c + d + getE();
                return sum;
            }

            public static int staticSum()
            {
                int sum = 0;
                sum = b + d;
                return sum;
            }

            public int getC()
            {
                return c;
            }
            public void setC(int c)
            {
                this.c = c;
            }
            public static int getD()
            {
                return d;
            }
            public static void setD(int d)
            {
                NestedStaticClass.d = d;
            }
        }
    }

    interface Sample
    {

    }

    class OneClass
    {
        int e = 10;
        static int f = 11;

        public int getE()
        {
            return e;
        }
        public void setE(int e)
        {
            this.e = e;
        }
        public static int getF()
        {
            return f;
        }
        public static void setF(int f)
        {
            OneClass.f = f;
        }

    }

单例只不过是一个类上的一次写入静态变量,一旦初始化,它总是引用自身的同一实例。

因此,您不能“使用单例代替静态变量”,也不能通过使用单例避免静态变量中的状态。

单例的优点只有一点:即使其他代码尝试重新初始化它一千次,它也不会被重新初始化。这对于像网络处理程序这样的东西来说非常棒,如果一个实例在等待响应的过程中被另一个实例替换,它会很糟糕。

除非你想要一个没有任何装置的整个应用程序,所有地方都是静态的-那么单例对于这些情况是有意义的,因为我们不能依靠缺少人为错误作为唯一的保证不会覆盖某些内容。

但要注意,单身汉并不能保证不会在任何地方生活。你的网络处理程序本身也可能依赖于其他单身者,等等。。。了不起的

而且,目前还没有编译器可以确保在编译时,单例是所有状态所在的地方,或者任何其他这样的想法所在的地方。在具有单例的类上可以有一百个静态变量。单例可以访问静态变量。编译器不会在意。

因此,我要提醒任何人,不要假设使用单例可以保证任何有关州生活的信息。它唯一的保证就是它是其类的唯一实例。这也是它唯一的优势。

其他答案所声称的单线图的任何其他优点都是编译器无法保证的,并且可能因语言而异。依赖注入是一种可能依赖于单例的补充模式,尽管它可能是或可能不是给定语言中的最佳解决方案或唯一解决方案。在缺少泛型的语言中,或者在调用静态访问器和函数时设置了任意限制,诉诸单例模式可能确实是解决给定问题的最佳解决方案。

在Swift这样的语言中,Singleton根本不需要获得依赖注入、可测试代码、良好管理的状态、线程安全访问器、多态性等。然而,它对于保证单一实例仍然有用。

概括一下:单例不过是一个静态变量,它可以防止给定类的多个实例存在,并防止单个实例被新实例覆盖。就这样,句号,句号。