理解java中static关键字

一. java为什么要引入static关键字

        转载:

        https://zhuanlan.zhihu.com/p/24373135?utm_source=com.example.android.notepad&utm_medium=social

        首先我们对比下几种语言写hello world的方式:

        理解java中static关键字

        可以看出Python和Scala是极其简明的,因为它们一个具体的操作可以脱离函数实体而直接运行的;C++稍微严谨一点,具体的操作需封装在函数中,执行函数来进行动作;而Java最为严格,所有的函数都必须封装在一个类中,函数不能脱离类单独存在。

        这样的规定显得java尤为死板,但语法的死板意味着更少的歧义,强对象使得Java成为了学习面向对象编程的最佳入门语言。但是凡事有利就有弊,强对象使得语法简单统一,同时也带来了很多不必要的麻烦。static就是为“洗地”应运而生的。

        很多变量和函数没必要封装在类中,强行封装显得很累赘,比如正则函数sin,变量π,随机函数random,这些函数或者常量值为什么要定义在类里呢?一定要定义的话,定义在哪个类里合适呢? 于是java把这些数学用到函数、常量封装在了Math类中。那么问题来了,如果用到sin,正常的写法是什么呢?

        Math math = new Math();

        double x = math.sin(x);

        每次用到函数就要new一个Math对象,显然是很不合理的,java语言的设计者也不会这么傻,所以,static登场了!当我们用static修饰一个函数或者变量的时候,就可以在不创建对象的情况下直接调用:Math.sin(x)。

        编程语言的关键字是有它内在的逻辑的,不要去死记硬背,通过上面的分析,我们就能知道static关键字用于修饰变量和函数是不得不这样做,而不是大家闲得慌,去加这么一个关键字故意去难为新手们。

        static 函数里不能使用this, super?废话!你只要明白了static 函数其实是全局函数,它只是因为Java的强对象的要求,而不得不找个类“挂靠”,它本身与任何类都没有关系。所以在static 方法里,当然不能直接访问某一个类的成员变量和成员函数了。但是呢,一个类让一个static函数挂靠了,总得有点好处吧?要说好处,倒也有一个,那就是类的成员函数调用static方法不用带类名了。

二. static关键字的三种用法

    1.修饰成员变量

        一个类构造出来的对象是相互独立的,每个对象保存这自己的成员变量,相互不影响。当用static修饰类中的一个变量,那么这个变量就不在归属于对象了,而是交给了类来管理,即无论new多少个对象,对象中的该变量都是唯一的,一个对象对该变量进行修改,那么所有的对象中该变量都会被修改。
        
          不过这样的静态变量会更加难以控制,所以一般不会这么用。通常共享一个变量可以用来计数:
          
            理解java中static关键字
            这样,每创建一个学生对象,学生数量就会加1。

      2.修饰静态方法

        不同于修饰变量,修饰静态成员方法对数据存储上没有多大的变化,因为类的方法本身就是存储在方法块中。那么修饰静态方法的用处是什么呢?正如上文提到的,修饰静态方法的最大作用就是可以在不创建对象的情况下直接调用,避免了new对象造成的繁琐以及消耗。但是也有它的局限性,就是静态方法不能调用其他非静态方法及变量,因为静态方法是在类没有new成对象之前就已经存在的,它并不知道它调用的方法或变量是哪个对象中的。

      3.静态块

        静态块较于静态方法的区别是:有些代码需要在项目启动时就执行,用到的是静态块,因为静态块可以在项目初始化时主动执行。
        一个类可以使用不包含在任何方法体中的静态块,当类被载入时,静态块执行,且只执行一次,所以静态块经常被用来执行类属性的初始化。
        
        那么初始化静态块的顺序时什么呢? 看以下代码: 

        理解java中static关键字
        它的执行结果:
        
        理解java中static关键字
        可以看出顺序: 父类的静态块 —> 子类的静态块 —>父类的非静态块 —> 父类的构造方法 —> 子类的非静态方法 —> 子类的构造方法。