Java - 关键字static

static关键字

· 静态修饰符
· 所谓静态是指在编译后所分配的内存会一直存在,直到程序退出内存才会释放这个空间,也就是只要程序在运行,那么这块内存就会一直存在。
· 这就导致了被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
· static可以修饰方法 变量 方法块

1.static 方法
static 方法又叫静态方法
《Java编程思想》P89 static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。
静态方法中不能访问非静态成员方法和非静态成员变量,但在非静态成员方法中可以访问静态成员方法/变量的:
在这里插入图片描述
可以看到3 24 25行有报错:
在这里插入图片描述
首先可以直接用MyObject.print2()说明了静态成员方法可以直接用类名.方法的格式调用,而不需要先示例化一个对象

另外这个例子中,非静态成员方法print1()可以访问静态成员变量str1和非静态成员变量str2,也可以访问静态成员方法print2()
但是 静态成员方法print2()只能访问静态成员变量str1.不能访问非静态成员变量str2和非静态成员方法print1().

我们最常见的static方法就是main方法,因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。

2.static变量
static变量也称作静态变量,在内存中也是单独的一块区域,被所有对象所共享!

在这里插入图片描述
输出结果是
在这里插入图片描述
可以看到TStatic类有两个构造方法,我们采用两种构造方法生成了两个对象:t,tt,他们都可以访问静态成员变量i,重点他们访问的是同一个成员变量.过程如下:
首先第10行构造方法生成的t,此时i的值是5
接着用了另一种无参的构造方法,生成了tt,此时i的值被更改为4
最后发现用对象t调用的成员变量i的值也是4
说明了所有对象访问的静态变量都是同一个.
为什么这样呢?
因为Java方法的参数传递机制是“值传递”

3.static 代码块
用static修饰代码块主要是为了简化代码,提高效率.
static代码块只会在类加载的时候执行一次
所以很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

需要注意的几个点:
4. Java中的static和C/C++不同,不能修改变量的访问权限
5. 虽然static方法是不能用this访问,但是this还是可以访问静态成员变量的
6. static不能修饰局部变量(这一点同public)(这只是一个说法,根据static作用域的生命周期)

常见面试题:
1.以下代码输出什么?
在这里插入图片描述
答案是:
在这里插入图片描述
这道题不仅考察了静态方法块,还考察了父类和之类的加载顺序.
main方法是程序的入口,但是在执行main方法之前,必须先加载testStatic1类,而在加载testStatic1类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载testStatic1类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。

2.这段代码又输出什么?
在这里插入图片描述

这个相对比较复杂了,输出:
在这里插入图片描述

首先加载Test类,因此会执行Test类中的static块。接着执行new MyClass(),而MyClass类还没有被加载,因此需要加载MyClass类。在加载MyClass类的时候,发现MyClass类继承自Test类,但是由于Test类已经被加载了,所以只需要加载MyClass类,那么就会执行MyClass类的中的static块。 在加载完之后,就通过构造器来生成对象。而在生成对象的时候,必须先初始化父类的成员变量,也就是说会执行Test中的Person person = new Person(),而Person类还没有被加载过,因此会先加载Person类并执行Person类中的static块, 在person对象生成完毕后,接着执行父类的构造器,完成了父类的初始化,然后就来初始化自身了,先初始化成员person,注意此时不用再执行Person类的static方法块了.最后执行MyClass的构造器。