Java修饰符 --- static
一、静态变量和静态方法
- 被 static 修饰的变量为类变量,也就是静态变量,可以直接通过
类名.变量名
引用,也可以通过 new 实例对象调用 - 被 static 修饰的方法为类方法,也就是静态方法,可以直接通过
类名.方法名
引用,也可以通过 new 实例对象调用 - 静态变量和静态方法统一属于类的静态资源,是类实例之间共享的,也就是
一处变,到处变
,是同步的,生命周期长,随类的创建而生,随类的结束而结束
二、静态变量和非静态变量的区别?
-
静态变量是属于类的,当且仅当在类初始化的时候加载,在内存只有一个副本,被所有对象(类实例)共享
-
非静态变量是对象的,每次创建对象的时候初始化,存在多个副本,各个对象拥有的副本互不影响
-
静态变量是存放在方法区的,而非静态变量在堆区
方法区:存放已经加载的类信息、常量、静态变量以及方法代码的内存区域
常量池:是方法区的一部分,主要用来存放常量和类中的符号引用等信息
堆区:用于存放类的对象实例
栈区:也叫 Java 虚拟栈,由一个一个的栈帧组成的先进后出的栈式结构,栈帧中存放方法运行时产生的局部变量、方法出口等信息,当调用一个方法时,虚拟机栈会创建一个栈帧存放这些数据,当方法完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶
创建新的栈帧
三、关于静态方法能否引用非静态资源等问题?
-
例子:
public class staticTest { private int number = 333; public static void main(String[] args) { number = 1; } }
这段代码编译都不会通过,运行的话会报错:无法从静态上下文中引用非静态变量
原因:
静态资源属于类,但是是独立于类存在的,存在方法区(静态区),JVM的类加载机制中,静态资源是在类初始化的时候加载,而非静态资源是在类
new
创建的时候加载,也就是说静态资源的初始化早于非静态资源。所有上述代码中,先执行 main 方法的时候,成员变量 number 还没初始化。总结:
静态方法只能引用静态资源,非静态方法可以引用静态资源和非静态资源
四、静态代码块
用于初始化一个类的时候做操作用的,静态块里的代码只在初始化的时候执行一次
执行顺序(双亲委托加载):
-
一个类:类内容(静态变量、静态初始化块)=> 实例内容(变量、初始化块、构造器)
-
继承关系类:父类(静态变量、静态初始化块)=> 子类(静态变量、静态初始化块)=> 父类(变量、初始化块、构造器)=> 子类(变量、初始化块、构造器)
-
例子:
public class staticTest { static { number = 333; System.out.println(number); } private static int number; }
注意:上面代码打印会报错:不能定义之前引用,也就是说:
静态代码块对应定义在它之后的静态变量,可以赋值,但是不能访问
五、静态内部类
-
静态内部类作用:
1.内部类一般只为其外部类使用
2.内部类存在外部类的引用,可以直接访问外部类属性
每个内部类都能单独继承一个接口,而无论外部类是否已经继承该接口(内部类使多重继承的解决方案更加完美)
-
外部类以对象的方式(创建对象访问)使用内部类,可以访问内部类所有的方法和属性,包括私有方法和属性
内部类不能访问外部类所在的局部变量,只能访问 final 修饰的局部变量
在方法内定义内部类时,如果内部类调用了方法中的变量,那么该变量必须申明为final类型,为什么?后来想到应该是生命周期的原因,因为方法内定义的变量是局部变量,离开该方法,变量就失去了作用,也就会自动被消除,而内部类却不会离开它所在方法就失去作用