美文网首页Java底层原理初探程序员
01.Java关键字与底层原理-static关键字

01.Java关键字与底层原理-static关键字

作者: Next_吴思成 | 来源:发表于2018-08-28 23:22 被阅读2次

    1.static关键字

    1.1.含义

    static方法就是没有this的方法,在static方法的内部不能调用非静态的方法,反过来倒是可以。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法,这实际上正是static方法的主要用途。[1]
    简单来说,就是不需要创建对象就能访问static修饰的方法,而static修饰的方法却不能直接调用非静态的方法。static关键字不仅仅能修饰方法,还可以修饰变量,那么引申开来,就是可以通过类直接访问由static修饰的变量。

    当然这只是其中的两个应用的方向,static关键字不仅仅能修饰方法和变量,还可以修饰代码块、类以及做静态导包使用,这其中的含义将在用法当中解释。对于没有写static的关键字的构造方法,以及接口里面的变量,他们都是具有static特性的,也在下面做一并的描述。

    1.2.用法与底层原理

    1.2.1.static变量

    • 用法

    static变量,就是不需要创建对象,直接通过类就能访问的变量。访问的形式为 类名.变量名,在类加载的时候就完成初始化,内存当中只有一份,所有的对象都共享这一个变量。需要对象之间共享变量的时候使用。

    public class Static{
      public static String staticVal = "static";
    }
    public class Main{
      public void method1() {
        System.out.println(Static.staticVal);
      }
    }
    
    • 底层原理

    这是一个简化版的内存解释,Java的内存包含了栈、堆和静态存储区,栈主要是存放对象的应用,堆是放对象,而静态存储区主要是放一些方法和常量。那么,如果我们有以下的对象:

    public class Person{
      public String name;
      public static Integer age;
    }
    public class Main{
      public static void main(String[] args) {
        Person person = new Person();
        person.name = "wusicheng";
        person.age = 18;
      }
    }
    

    那么他们在内存当中的分配情况如下图所示:


    注意nameage存储位置的不同,name是存储存储到堆上面的,和对象绑定在一起,而age是Person类进行管理的,存储在静态存储区上面,不论建立多少个对象,都只指向这个一个地方。在类加载的时候,静态存储区中的内容已经初始化完成,所以在内存当中就只有这一份。

    1.2.2.static方法

    static方法就是可以使用 对象.方法名(方法参数...) 进行访问的方法,静态方法当中,不可以直接调用非静态的方法。具体的使用如下

    public class Static{
      public void notStatic() {
        //todo
      }
      public static void staticMethod() {
        System.out.println("===静态方法===");
        notStatic();//error 不可以这么调用,会报错
      }
    }
    public class Main{
      public void method1() {
        Static.staticMethod();
      }
    }
    
    • 底层原理

    略,后面进行补充。

    1.2.3.static代码块

    static静态代码块的作用是初始化一些静态变量使用的,在static代码块里面,可以调用静态变量方法。

    public class Static{
      public static List<String> staticList = new ArrayList<>(2);
      static {
        staticList.add("static1");
        staticList.add("static2");
      }
    }
    public class Main{
      public void method1() {
        System.out.println(Static.staticList.get(0));
      }
    }
    
    • 底层原理

    略,以后补充。

    1.2.4.static类

    static修饰类,只能够在静态内部类当中使用,所谓的静态内部类,就是在类里面套一层类,并且这个类是使用static修饰的。这样做可以把一个类隐藏到外部类里面,而且不需要内部类引用外围类对象。

    public class Static{
      public static class InnerStaticClass {
        public void method() {
          System.out.println("===InnerStaticClass====");    
        }
      }
    }
    public class Main{
      public void method1() {
        Static.InnerStaticClass innerClass = new Static.InnerStaticClass();
      }
    }
    

    1.2.5.静态导包

    静态导包是简化书写使用的,使用了静态导包之后,就可以直接使用相关的静态变量,静态方法,不需要使用类名.变量类名.方法来进行调用,一般的使用场景是junit判断是否相等的情况下使用。

    import static java.lang.Math.PI;
    public void method() {
        System.out.println(PI);
    }
    

    1.2.6.接口当中的变量

    接口当中可以定义成员变量,而且定义的成员变量一定是public static final的,但是在实际的书写过程中,可以把public static final给去掉,例如下面的两种写法是一样的。

    public interface StaticInterface {
        String staticVal = "static val in interface";
        public static final String staticVal2 = "static val in interface";
    }
    public class Main {
        public void mehod() {
            /**接口当中的变量*/
            System.out.println(StaticInterface.staticVal);
            System.out.println(StaticInterface.staticVal2);
        }
        public static void main(String[] args) {
            new Main().mehod();
        }
    }
    
    • 底层原理

    略,后面补上。

    1.3. 实际应用

    static关键字,一般都是用在工具类里面,工具类只需要一套,载入内存的时候对这些变量和方法进行初始化就可以了,不需要每一次都创建对象,然后调用相应的变量和方法,否则会浪费过多的内存资源。但是,如果static的变量和方法太多,而这些变量和方法是在JVM关闭的时候才进行清理的,在就会造成内存的浪费,而且可以回导致内存溢出。

    对于程序当中常用的变量,而且基本不需要变更的,也可以使用static关键字进行修饰然后使用static静态代码块进行初始化,那么程序在调用的时候就可以直接在内存中拿来就用,不需要再堆上面再分配空间,然后初始化成一样的数据,这样会降低效率而且会浪费内存。基于这个原因,JUnit使用@BeforeClass注解的方法,必须是static方法的原因就显而易见了,因为在单元测试当中,@BeforeClass是在单元测试载入时候初始化相关的数据使用的,而且这些数据是一整类都通用,那么让他们初始化到内存当中,用的时候直接调可以大大节约时间和空间。

    1.4. 总结

    1. static关键字修饰的会在类加载完成的时候就初始化到内存当中,直到JVM关闭;
    2. static关键字修饰的变量和方法是通过"类名.变量"和"类名.方法"调用的;
    3. static方法当中不能使用this,它是类管理的,不是对象管理的,同时也不能使用super;
    4. 接口里面的成员变量默认都是public static final的;
    5. static关键字常用在工具类当中或者只需要初始化一次的方法上。

    https://www.jianshu.com/p/92327e300a6e


    1. 来自《Java编程思想》

    相关文章

      网友评论

        本文标题:01.Java关键字与底层原理-static关键字

        本文链接:https://www.haomeiwen.com/subject/qoqxwftx.html