static可修饰成员变量、方法、代码块、内部类
一、 静态变量
static修饰的变量称之为静态变量/类变量。
静态变量随着类的加载而加载到方法区中的静态区,并且在静态区中赋予了初始值。静态变量在对象之前产生,所以可以不通过对象而通过类名来调用,也可以通过对象来调用。但是一般是通过类名来调用的。
由于类创建的所有对象存储的是静态属性在方法区中的静态区中的地址值,所以静态变量是被所有对象所共享,如果一个发生变化,其他的也随之变化。—尽量少用静态属性(涉及到安全性的问题)。
主函数在JVM调用它的时候执行。在主类中找到主方法,通过一步步的解析,将主函数加载到栈内存(在编译和加载的过程中并不会执行)
在堆中的对象中存放的是静态属性的地址,顺着这个地址可以找到方法区的静态区的静态变量,从而获取它的值。
由于对象存储的是静态变量在静态区中的地址,所以所有的对象共用有一个静态变量。
静态变量可以定义在函数里面吗?—不可以—静态变量是随着类的加载而加载并初始化。方法是随着类的加载而加载到方法区,但是没有执行,是在方法被调用的时候执行,所以说静态变量是不能存在不存在的方法中。
问题1、静态变量可以定义在函数里面吗?
不可以
静态变量是随着类的加载而加载并初始化。方法是随着类的加载而加载到方法区,但是没有执行,是在方法被调用的时候执行,所以说静态变量是不能存在不存在的方法中。
问题2、构造代码块中可以定义静态变量吗?
不可以
构造代码块是在对象创建的时候执行(new的时候才会被调用),而静态变量是在类加载的时候加载并且初始化。时间有冲突。静态变量是不能存在不存在的方法中。
问题3、在函数/构造代码块中初始化(在程序中第一次给值)静态变量吗?
可以
构造代码块是在创建对象的的时候执行,每创建一个对象执行一次。静态代码块是先于构造代码块存在的,所以使用已有的变量是可以的。
问题4、可以通过this或者super调用静态变量吗?
可以
因为静态变量可以通过对象来调用。
二、静态方法
静态方法也叫类方法。随着类的加载而加载到方法区中的静态区且只加载一次。(普通的方法是存在方法区中的普通区,静态方法是存在与方法区中的静态区)静态方法先于对象存在,所以静态方法可以不通过对象而通过类名来调用,也可以通过对象来调用,但是一般不这样做。
静态区中的元素不归属于某个具体的对象,而是归属于某个类的。
比如:
Arrays.copyOf()
Arrays.toString()
System.arraycopy()
注意:类向方法区中只加载一次,然后会一直存在方法区中,直到程序运行结束 |
问题1、静态方法中可以定义静态变量吗?
不可以
静态方法加载到静态区只是存储在静态区但是并没有执行,只有被调用的时候才会到栈中去执行,在执行的时候才会给其中的变量的分配内存空间。而静态变量在随着类加载到方法区中的静态区时就已经分配好内存空间并且初始化了。所以时间上会起冲突。
问题2、静态方法可以直接调用本类中的非静态属性/方法吗?
不可以
非静态方法必须通过对象来调用。静态方法可以通过类来调用,执行静态方法的时候不一定有对象存在。所以不能使用非静态的方法。静态方法不可以直接调用本类中非静态的属性和方法,但是在静态方法中可以通过对象来间接的调用本类中非静态的属性或方法。
问题3、可以在主函数中使用this吗?
不可以
问题4、静态方法可以重载吗?
可以
重载的硬性条件是方法名一致且参数列表不同,与修饰符并没有关系。
问题5、静态方法可以重写吗?
不可以
子类不可以重写父类的静态方法。但是可以存在与父类方法签名一致的静态方法。
问题6、父子类中可以存在方法签名一致的静态方法吗?
可以
静态是从类层面上来看的,而重写是针对对象而言的
三、静态代码块
在类内使用static{}
静态代码块是随着类的加载而加载到方法区中的静态区,在类创建对象或者执行方法之前执行一次。静态代码块只执行一次,在类加载的时候执行
有继承关系的类,生成子类对象的执行顺序:
在创建子类对象的时候需要先创建父类对象。
①加载父类
②执行父类的静态代块
③执行子类的静态代码块
④父类的构造代码块
⑤父类的构造方法
⑥子类的构造代码块
⑦子类的构造方法
若生成了多个子类对象,则在上面的基础上,执行
父类的构造代码块
父类的构造方法
子类的构造代码块
子类的构造方法。
总的来说,执行顺序为
父类的静态(静态代码块和静态属性谁先定义谁先执行)—子类静态(静态代码块和静态属性谁先定义谁先执行)–—父类成员变量(构造代码块)谁先定义谁先执行—父类的构造方法—子类成员变量(构造代码块)谁先定义谁先执行子类的非静态—子类的构造方法。
构造代码块和成员变量是同等级的,谁先定义谁先执行
程序启动的时候先加载核心类库到方法区。(如果核心类中有静态方法时,把静态方法单独加载到静态区),其次是加载主函数所在的类,接着是调用主函数,执行主函数,执行主函数的时候,遇到新的类,在方法区不存在,则会把该类加载到方法区(也就是说类在第一次使用的时候才会加载),类一旦加载到方法区就不会在移除(也就是说类只会被加载一次,一直存储在方法区,直到程序执行完毕)