static,修饰静态变量,静态方法,静态代码块。
1、用途:
随着类的加载而加载
优先于对象存在
被所有对象所共享
可以直接被类名调用
生命周期和类保持一样,static变量的生命周期取决于类的生命周期
2、Classn classname = new Classn("xxx");
这句话都做了哪些事情?
1、找到Classn.class并加载进内存
2、找到static静态代码块,进行静态初始化。(static修饰的成员只执行一次,故而经常进行初始化)
3、在堆内存开辟地址
4、进行初始化
5、进行变量赋值,将栈指针classname指向开辟的堆内存
3、实例变量和类变量的区别
存放位置
类变量随着类的加载而存在于方法区中
实例变量随着对象的建立而存在堆内存中
生命周期
类变量生命周期最长,随着类的消失而消失
实例变量生命周期随着对象的消失而消失
局限性:
静态只能访问静态
生命周期过长
4、jvm重要区域和static的位置
方法区:在java的虚拟机中有一块专门用来存放已经加载的类信息、常量、静态变量以及方法代码的内存区域,叫做方法区。
常量池:常量池是方法区的一部分,主要用来存放常量和类中的符号引用等信息。
堆区:用于存放类的对象实例。
栈区:也叫java虚拟机栈,是由一个一个的栈帧组成的后进先出的栈式结构,栈桢中存放方法运行时产生的局部变量、方法出口等信息。当调用一个方法时,虚拟机栈中就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶创建新的栈桢。
5、静态绑定与动态绑定
//被调用的类
packagehr.test;
classFather{
publicstaticvoidf1(){
System.out.println("Father— f1()");
}
}
//调用静态方法
importhr.test.Father;
publicclassStaticCall{
publicstaticvoidmain(){
Father.f1();//调用静态方法
}
}
在Father类所在的方法区中找到f1()方法的直接地址,并将这个直接地址记录到StaticCall类的常量池索引为13的常量表中。这个过程叫常量池解析,以后再次调用Father.f1()时,将直接找到f1方法的字节码。
这种在编译阶段就能够确定调用哪个方法的方式,我们叫做 静态绑定机制。
packagehr.test;
//被调用的父类
classFather{
publicvoidf1(){
System.out.println("father-f1()");
}
publicvoidf1(inti){
System.out.println("father-f1() para-int "+i);
}
}
//被调用的子类
classSonextendsFather{
publicvoidf1(){//覆盖父类的方法
System.out.println("Son-f1()");
}
publicvoidf1(charc){
System.out.println("Son-s1() para-char "+c);
}
}
//调用方法
importhr.test.*;
publicclassAutoCall{
publicstaticvoidmain(String[] args){
Father father=newSon();//多态
father.f1();//打印结果: Son-f1()
}
}
根据对象(father)的声明类型(Father)还不能够确定调用方法f1的位置,必须根据father在堆中实际创建的对象类型Son来确定f1方法所在的位置。这种在程序运行过程中,通过动态创建的对象的方法表来定位方法的方式,我们叫做 动态绑定机制。