Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 单人公开静态决赛_Java_Singleton - Fatal编程技术网

Java 单人公开静态决赛

Java 单人公开静态决赛,java,singleton,Java,Singleton,我一直在想Java中的单例。按照惯例,单身人士是这样设置的: private static MyClass instance = null; public static MyClass getInstance(){ if (instance == null){ instance = new MyClass(); } return instance; } private MyClass(){} 最近,我改用以下方法: public static final

我一直在想Java中的单例。按照惯例,单身人士是这样设置的:

private static MyClass instance = null;
public static MyClass getInstance(){
    if (instance == null){
        instance = new MyClass();
    }
    return instance;
}
private MyClass(){}
最近,我改用以下方法:

public static final MyClass instance = new MyClass();
private MyClass(){}

这要短得多,速度也快得多,因为没有空检查,而且键入MyClass.instance比键入MyClass.getInstance感觉更好。第二个版本不是主流的方法,有什么原因吗?

第一个版本在第一次实际需要时创建实例,而第二个版本则在类运行时立即运行构造函数

类或接口类型T将在 首次出现以下任何一种情况:

public static final MyClass instance = new MyClass();
private MyClass(){}
T是一个类,并且创建了T的一个实例。 T是一个类,调用由T声明的静态方法。 分配了一个由T声明的静态字段。 使用由T声明的静态字段,该字段不是常量 变量§4.12.4。 T是顶级类别§7.6,是断言声明§14.10 执行T§8.1.3中的词汇嵌套。[...] 在类和中调用某些反射方法 包java.lang.reflect也会导致类或接口初始化

首次使用时的初始化是一种性能改进,如果构造函数中的代码进行了昂贵的操作,则可以加快应用程序的启动。另一方面,第二个版本易于阅读,并且是自动线程安全的

无论如何,最先进的技术并不是以任何一种方式创建单例:对于一堆KB,您可以获得使其适合您的依赖注入库,并且还可以处理更复杂的场景,例如查看Spring和AOP支持的注入


注意:第一个版本在粘贴的代码段中不是线程安全的

第一个版本在第一次实际需要时创建实例,而第二个版本越短,则在类完成后立即运行构造函数

类或接口类型T将在 首次出现以下任何一种情况:

public static final MyClass instance = new MyClass();
private MyClass(){}
T是一个类,并且创建了T的一个实例。 T是一个类,调用由T声明的静态方法。 分配了一个由T声明的静态字段。 使用由T声明的静态字段,该字段不是常量 变量§4.12.4。 T是顶级类别§7.6,是断言声明§14.10 执行T§8.1.3中的词汇嵌套。[...] 在类和中调用某些反射方法 包java.lang.reflect也会导致类或接口初始化

首次使用时的初始化是一种性能改进,如果构造函数中的代码进行了昂贵的操作,则可以加快应用程序的启动。另一方面,第二个版本易于阅读,并且是自动线程安全的

无论如何,最先进的技术并不是以任何一种方式创建单例:对于一堆KB,您可以获得使其适合您的依赖注入库,并且还可以处理更复杂的场景,例如查看Spring和AOP支持的注入


注意:在粘贴的代码段中,第一个版本不是线程安全的,您首先描述的方式称为延迟实例化,即仅在第一次调用对象时才会创建该对象。此方法不是线程安全的,因为第二个线程可以创建第二个实例

如果您阅读以下书籍:

约书亚·布洛赫的《有效的Java》

他解释说,单例模式的最佳实现是通过使用枚举:

然后,您可以通过Enum调用您的singleton,如下所示:

public class Test {

    public void test(){
        Singleton.INSTANCE.doSomething();
    }
}

这很符合你所说的,因为它看起来写起来更漂亮、更短,但也保证不会有第二个实例

您首先描述的方式称为延迟实例化,即仅在第一次调用对象时才会创建该对象。此方法不是线程安全的,因为第二个线程可以创建第二个实例

如果您阅读以下书籍:

约书亚·布洛赫的《有效的Java》

他解释说,单例模式的最佳实现是通过使用枚举:

然后,您可以通过Enum调用您的singleton,如下所示:

public class Test {

    public void test(){
        Singleton.INSTANCE.doSomething();
    }
}

这很符合你所说的,因为它看起来写起来更漂亮、更短,但也保证不会有第二个实例

同步线程的最佳方法是使用双重检查,以确保一次只有一个线程进入同步块,并避免每次执行代码时获得锁

public class DoubleCheckLocking {

    public static class SearchBox {
        private static volatile SearchBox searchBox;

        // private attribute of this class
        private String searchWord = "";
        private String[] list = new String[]{"Stack", "Overflow"};

        // private constructor
        private SearchBox() {}

        // static method to get instance
        public static SearchBox getInstance() {
            if (searchBox == null) { // first time lock
                synchronized (SearchBox.class) {
                    if (searchBox == null) {  // second time lock
                        searchBox = new SearchBox();
                    }
                }
            }
            return searchBox;
        }
}

同步线程的最佳方法是使用Double Check,以确保一次只有一个线程进入同步块,并避免每次执行代码时获得锁

public class DoubleCheckLocking {

    public static class SearchBox {
        private static volatile SearchBox searchBox;

        // private attribute of this class
        private String searchWord = "";
        private String[] list = new String[]{"Stack", "Overflow"};

        // private constructor
        private SearchBox() {}

        // static method to get instance
        public static SearchBox getInstance() {
            if (searchBox == null) { // first time lock
                synchronized (SearchBox.class) {
                    if (searchBox == null) {  // second time lock
                        searchBox = new SearchBox();
                    }
                }
            }
            return searchBox;
        }
}

我可以想到两个原因:

金融机构 rst是封装:在类暴露于客户机代码之后,您可能会重新考虑初始化单例的方式和时间。初始化方法为您以后更改策略提供了更多的自由。例如,您可能会改变主意,根据运行时另一个静态变量的值,决定使用两个不同的构造函数,而不是一个。对于您的解决方案,在将类加载到内存时,您必须只使用一个构造函数,而对于getInstance,您可以更改初始化逻辑,而不会影响到客户端代码的接口

第二种是延迟初始化:使用传统的单例实现,只有当客户端代码第一次需要时,MyClass对象才会加载到内存中。如果客户端代码根本不需要它,则可以节省应用程序分配的内存。请注意,在程序运行之前,可能无法确定是否需要单例。例如,它可能取决于用户与程序的交互

但是,延迟初始化并不是您一定想要的。例如,如果您正在编程一个交互式系统,并且单例的初始化非常耗时,那么在加载程序时初始化它可能比在用户已经与它交互时更好,因为后者可能会在第一次调用getInstance时导致系统响应延迟。但在这种情况下,您可以使用public方法初始化实例,如下所示:

private static MyClass instance = getInstance();

我可以想到两个原因:

第一个是封装:在类暴露于客户机代码之后,您可能会重新考虑初始化单例的方式和时间。初始化方法为您以后更改策略提供了更多的自由。例如,您可能会改变主意,根据运行时另一个静态变量的值,决定使用两个不同的构造函数,而不是一个。对于您的解决方案,在将类加载到内存时,您必须只使用一个构造函数,而对于getInstance,您可以更改初始化逻辑,而不会影响到客户端代码的接口

第二种是延迟初始化:使用传统的单例实现,只有当客户端代码第一次需要时,MyClass对象才会加载到内存中。如果客户端代码根本不需要它,则可以节省应用程序分配的内存。请注意,在程序运行之前,可能无法确定是否需要单例。例如,它可能取决于用户与程序的交互

但是,延迟初始化并不是您一定想要的。例如,如果您正在编程一个交互式系统,并且单例的初始化非常耗时,那么在加载程序时初始化它可能比在用户已经与它交互时更好,因为后者可能会在第一次调用getInstance时导致系统响应延迟。但在这种情况下,您可以使用public方法初始化实例,如下所示:

private static MyClass instance = getInstance();

反射:反射可以导致破坏单态 singleton类的属性,如下例所示:

 // Java code to explain effect of Reflection 

 import java.lang.reflect.Constructor; 

 // Singleton class 
 class Singleton  
 { 
     // public instance initialized when loading the class 
     public static Singleton instance = new Singleton(); 

     private Singleton()  
     { 
         // private constructor 
     } 
 } 

 public class GFG  
 { 

     public static void main(String[] args) 
     { 
         Singleton instance1 = Singleton.instance; 
         Singleton instance2 = null; 
         try
         { 
             Constructor[] constructors =  
                     Singleton.class.getDeclaredConstructors(); 
             for (Constructor constructor : constructors)  
             { 
                 // Below code will destroy the singleton pattern 
                 constructor.setAccessible(true); 
                 instance2 = (Singleton) constructor.newInstance(); 
                 break; 
             } 
         } 

         catch (Exception e)  
         { 
             e.printStackTrace(); 
         } 

     System.out.println("instance1.hashCode():- " 
                                       + instance1.hashCode()); //366712642
     System.out.println("instance2.hashCode():- " 
                                       + instance2.hashCode()); //1829164700
     } 
 } 



反射:反射可以导致破坏单态 singleton类的属性,如下例所示:

 // Java code to explain effect of Reflection 

 import java.lang.reflect.Constructor; 

 // Singleton class 
 class Singleton  
 { 
     // public instance initialized when loading the class 
     public static Singleton instance = new Singleton(); 

     private Singleton()  
     { 
         // private constructor 
     } 
 } 

 public class GFG  
 { 

     public static void main(String[] args) 
     { 
         Singleton instance1 = Singleton.instance; 
         Singleton instance2 = null; 
         try
         { 
             Constructor[] constructors =  
                     Singleton.class.getDeclaredConstructors(); 
             for (Constructor constructor : constructors)  
             { 
                 // Below code will destroy the singleton pattern 
                 constructor.setAccessible(true); 
                 instance2 = (Singleton) constructor.newInstance(); 
                 break; 
             } 
         } 

         catch (Exception e)  
         { 
             e.printStackTrace(); 
         } 

     System.out.println("instance1.hashCode():- " 
                                       + instance1.hashCode()); //366712642
     System.out.println("instance2.hashCode():- " 
                                       + instance2.hashCode()); //1829164700
     } 
 } 



您将单例和惰性实例化混为一谈。第一个版本不是线程安全的。第二个是@biziclop指出的:P.@VinodMadyalkar第二个例子有什么线程不安全的地方?但是如果提问者只是编写不应该是多线程的应用程序呢?那么我认为他对线程安全不太关心。线程安全甚至不是这个问题的重点@VinodMadyalkar@biziclop-谢谢你提醒我填满我的咖啡杯:你把单例和惰性实例化混为一谈了。第一个版本不是线程安全的。第二个是@biziclop指出的:P.@VinodMadyalkar第二个例子有什么线程不安全的地方?但是如果提问者只是编写不应该是多线程的应用程序呢?那么我认为他对线程安全不太关心。线程安全甚至不是这个问题的重点@VinodMadyalkar@biziclop-谢谢你提醒我装满咖啡杯:P你能详细说明这两种方法的优点吗?这取决于MyClass在其构造函数中做了什么。例如,如果从数据库加载数据以填充缓存,需要30秒,如果还有其他类似的类,则整个启动过程可能需要一些时间。这是可以优化的,尤其是在启动应用程序后,如果不是所有这些类都需要的话。如果可以立即实例化MyClass,那么您的第二个解决方案是绝对合适的
这两种方法的优点是什么?这取决于MyClass在其构造函数中执行的操作。例如,如果从数据库加载数据以填充缓存,需要30秒,如果还有其他类似的类,则整个启动过程可能需要一些时间。这是可以优化的,尤其是在启动应用程序后,如果不是所有这些类都需要的话。若可以立即实例化MyClass,那个么您的第二个解决方案是绝对合适的。最好的方法是使用枚举单例。DCL是90年代最流行的。最好的方法是使用枚举单例。DCL现在是90年代,这确实是最好的推荐方式。您可以免费获得延迟加载,但要保持机制极其简单。这确实是最好的推荐方式。您可以免费获得延迟加载,但保持机制极其简单。