preface

Static variables and methods are used in many applications, but there are many problems when they are used. Static variables and methods are used in many applications.

  • A static variable
  • A static method
  • Static code block
  • Static inner class
  • Static imports

Let’s take a look at these uses.

A static variable

A static variable is a class that has only one instance in memory. When the class is loaded, memory is allocated for the static variable.

Stored in the method area with the class itself is never recycled unless the JVM exits. (What else can be found in the methods area: Java Virtual Machine run-time data area)

Static variables can be used as: class name. Variable name and object. Variable name.

【 example 】 The date formatting class SimpleDateFormat will be used frequently in the actual development. When necessary, a new object will be used directly.

But we know that creating objects frequently is bad, so create a static SimpleDateFormat global variable directly in DateUtil and use that instance to operate directly, saving performance because of memory sharing.

However, it has thread safety problems under high concurrency. SimpleDateFormat Thread safety problem

public class OuterStatic {
 
  public static class InnerStaticSimpleDateFormat  implements Runnable {
        @Override
        public void run() {
          while(true) {
            try {
              Thread.sleep(3000);
                System.out.println(Thread.currentThread().getName() +":"+DateUtil.parse("The 2017-07-27 08:02:20"));
            } catch (Exception e) {
                e.printStackTrace();
            }
          }
        }    
    }
    public static void main(String[] args) {
      for(int i = 0; i < 3; i++){
         new Thread(new InnerStaticSimpleDateFormat(), "Test thread").start();

      }
    }
}
class DateUtil {
    
    private static  volatile SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    public static  String formatFromDate(Date date)throws ParseException{
        return sdf.format(date);
    }
    public static Date parseToDate(String strDate) throws ParseException{
        returnsdf.parse(strDate); }}Copy the code

Although there is a volatile object is visible, but after running a certain risk to Java. Lang. A NumberFormatException: multiple points or For input string: “” error, such as the reason is multi-threaded to operate an object

The solutions are as follows:

  • Use private objects
  • lock
  • ThreadLocal.
  • Use a third-party date handler.
  • Java8 introduces thread-safe, easy, highly reliable time package, which has LocalDateTime year month day ten minutes and seconds; LocalDate date; Three classes LocalTime time are available.

The following diagram illustrates the use of private objects and ThreadLocal to address high concurrency.

This article gives the use of private objects and locking two implementation code, ThreadLocal readers can try their own implementation

public class DateUtil {

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      
    public static String formatFromDate(Date date)throws ParseException{
      // Method 1: leave memory unshared, create private objects when used, comment out the global variable SDF when used
      //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      //return sdf.format(date);
      // Open the comment for the global variable SDF
        synchronized(sdf){
            return sdf.format(date);
        }  
    }
   public static Date parseToDate(String strDate) throws ParseException{
       // Comment out the global variable SDF
       //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       //return sdf.parse(strDate);
       // Open the comment for the global variable SDF
        synchronized(sdf){
            returnsdf.parse(strDate); }}}Copy the code

A static method

Static and non-static methods, like the class itself, are stored in memory and are never reclaimed unless the JVM exits. One of the differences they use is that non-static methods need to be called by the instance, whereas static methods are called directly by the class name.

Singleton pattern, which provides the best way to create objects, ensures that there is only one instance of a class, and provides a global access point to it.

public class Singleton {
   private static volatile Singleton instance = null;  
    static {  // Static code block, described later
       instance = new Singleton();  
    }  
    private Singleton (){}  
    public static Singleton getInstance() {  
        returninstance; }}Copy the code

Static method does not need to instantiate can be directly used, convenient usage, do not frequently open up space for objects and objects are recycled, saving system resources. Is static more pleasant? But it also brings some problems:

Static order export (); static order export ();

public class ExportExcelUtil{
    @Autowired
    private static OrderService orderService ;

    public static void exportExcel(String id){
       // Query the order data to export
       Order order =orderService.getById(id);// The orderService object here will be null
      / /... Omit export code...}}Copy the code

Why is orderService null? The reason is not that Spring does not inject, but that static methods “empty” it.

Solution 1: @postConstruct, which decorates methods that are executed once when the Servlet is loaded by the server, looks like this:

@Component // This annotation must be added
public class ExportExcelUtil{
    @Autowired
    OrderService orderService ;

    private static ExportExcelUtil  exportExcelUtil; 

    // @postconstruct is basically a code block that is declared to be executed when you load a class constructor,
    // Copy the service to a static service after the constructor is loaded.
     @PostConstruct  
     public void init() {       
        exportExcelUtil= this; 
        exportExcelUtil.orderService = this.orderService ; 
     }  

    public static void exportExcel(String id){
       // Does it look like the classic main method?
       Order order =exportExcelUtil.orderService .getById(id);
       / /... Omit export code...}}Copy the code

Every utility class has to be annotated with @postConstruct, which makes code repeatable. Can we get the Bean instance directly from the Spring container?

Solution 2: ApplicationContextAware. The Spring container automatically injects context objects into the setApplicationContext method in the implementation class of the ApplicationContextAware interface.

In other words, we can get beans in the Spring container from this context object in the implementation class of ApplicationContextAware.

First, configure the Listener to load the Spring container in web.xml in your Web project:

<! Initialize the Spring container, Let the Spring container start automatically when the Web application starts --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>Copy the code

Then, implement the ApplicationContextAware interface:

public class SpringContextBean implements ApplicationContextAware{
 private static ApplicationContext context = null;

 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
 {
  context = applicationContext;
 }

 public static <T> T getBean(String name)
 {
  return (T)context.getBean(name);
 }

 public static <T> T getBean(Class<T> beanClass){
  returncontext.getBean(beanClass); }}Copy the code

Finally, register the utility class in the Spring configuration file:

<bean id="springContextBean" class="com.test.SpringContextBean"></bean>
Copy the code

The original export utility class code can be simplified as follows:

public class ExportExcelUtil{
    public static void exportExcel(String id){
      OrderService orderService = SpringContextBean.getBean(OrderService.class);
      Order order =orderService .getById(id);
       / /... Omit export code...}}Copy the code

Static code block

We actually use code blocks all the time in our work. A code block is a piece of code surrounded by {}.

Where the static code block is executed only once, the construction code block is executed each time the object is created.

Code blocks can be divided into four types according to their location: normal code blocks, construction blocks, static code blocks, and synchronous code blocks.

Because the JVM only allocates memory statically once, memory allocation for static variables is done during class loading.

So in practice we can use static code blocks to initialize some immutable properties:

//final indicates that the map set is unchangeable
public  static  final  Map<String,String> spuKeysMap = new HashMap<String,String>();
static{
   spuKeysMap.put("spuName"."Men's");
   spuKeysMap.put("spuCode"."Menswear code");
   spuKeysMap.put("spuBrand"."Brand");
   spuKeysMap.put("owner"."Owner");
}
Copy the code

But what does a static code block have to do with static variable initialization? In the singleton pattern above, we used static blocks of code to create objects. Why did we write that way? I saw this code on the Internet:

static {  
    _i = 10;  
}  
public static int _i = 20;  

public static void main(String[] args) {  
    System.out.println(_i);  
} 
Copy the code

Is the result 10 or 20? What if there are multiple code blocks?

static {  
     _i = 10;  
}  
public static int _i =30;
static {  
    _i = 20;  
}   
public static void main(String[] args) {  
    ystem.out.println(_i);
}
Copy the code

And then you’ll see that both answers are 20.

Public static int I = 10; This is no different from the following code, which is exactly the same bytecode after compilation (the reader can view the bytecode file using the javap -c command), so the result of the two examples is the value of the last assignment.

public static int _i;  
static {  
    _i = 10;  
}
Copy the code

Static inner class

An inner class becomes a static inner class when you define it with the permission modifier static.

Instantiate (getInstance, getInstance, getInstance, getInstance, getInstance, getInstance, getInstance, getInstance, getInstance, getInstance); Due to the poor performance of hankhan writing method, the final singleton mode was optimized as follows:

public class Singleton {
    // Use static inner classes to initialize objects
    private static class  SingletonHolder{
      private static volatile Singleton instance = new Singleton();   
    }
    private Singleton (){}  
    public static Singleton getInstance() {  
        return SingletonHolder.instance;  
    }    
    public static  void otherMothed(){
      System.out.println("Objects are not created when other methods of a singleton are called.")
    }  
    public static  void  main(String [] args){
        //Singleton.otherMothed();Singleton.getInstance(); }}Copy the code

There is not much use of the inner class for bloggers in practical development, but sometimes it is necessary to do without it. For example, LinkedList uses the following static inner class:

In fact, we refer to next and prev as Pointers to the front and back nodes in the data structure, and the static array of internal class Entry is also used to store data in HashMap.

To understand this, you can run the following code to experience static inner classes for yourself.

private static String name = "Beijing";  // Static variables
  public static void main(String[] args) { 
    new StaticInternal().outMethod();
  }   
  public static void outStaticMethod(String tempName) {       
      System.out.println("Static method name of external class :"+tempName);  
  } 
  public void outMethod() {             // An external class accesses a static member of a static inner class: the inner class. Static members
    System.out.println("Non-static method calls to external classes");
      StaticInternal.InnerStaticClass inner = new   StaticInternal.InnerStaticClass();// Instantiate the static inner class object
    inner.setInnerName("Fast");// Access non-static methods of static inner classes
    InnerStaticClass.innerStaticMethod(); // Access static methods of static inner classes
    System.out.println("External class access static inner class non-static method name:"+inner.getInnerName());
}

static class InnerStaticClass {            
  String  InnerName="Xi 'an";  
    static void innerStaticMethod() {    // Static inner class static method
        System.out.println("Static inner class access static variable of external class: name =" + name);  
        outStaticMethod(new InnerStaticClass().InnerName);     // Access static methods of the external class
    }  
    // Static inner class non-static method
    public void setInnerName(String name) {  
        System.out.println("Non-static methods of static inner classes");  
        this.InnerName = name;  
    }  
    public String getInnerName() {  
      System.out.println("Static inner class non-static get method name="+name); 
        returnthis.InnerName; }}Copy the code

Here’s a summary of static inner classes:

  • Enhance code readability. Such as:

    StaticInternal.InnerStaticClass inner 
    = new StaticInternal.InnerStaticClass();
    Copy the code
  • Objects of multiple external classes can share objects of the same static inner class.

  • A static inner class does not need to depend on an external class; it can exist independently of an external object. Because static classes and methods belong only to the class itself, they do not belong to the objects of that class, much less to the objects of other external classes.

Static imports

Static import is a new feature added after JKD1.5. It is not commonly used. Sometimes this can come out of an interview and make other people think you love technology.

Recall that we used to write random numbers like this:

public static void main(String[] args) {
  double random = Math.random();
  System.out.println(Math.PI);
  System.out.println(Math.round(random));
}
Copy the code

Math comes up too often. Can it be simplified? Now we can write directly using static imports as follows

import static java.lang.Math.*;

public class StaticInternal {
 
  public static void main(String[] args) {
      double random = random();
      System.out.println(PI);
      System.out.println(round(random)); }}Copy the code

Is it much more convenient? Don’t be lazy, though, because using it too much can lead to code readability:

import static java.lang.Math.*;
import static java.lang.Integer.*;
public class StaticInternal {
 
  public static void main(String[] args) {
 double random = random();
 System.out.println(PI);
 System.out.println(round(random));
 System.out.println(bitCount(11)); }}Copy the code

You probably know that PI is a method of the Math class, but which class is bitCount? Avoid using static imports.

Really want to import, remove the * wildcard, direct written: Java. Lang. Integer. BitCount.

From: my.oschina.net/liughDevelo…

Give a [look], is the biggest support for IT elder brotherCopy the code