static 关键字
static 静态的
static 可以修饰内部类(这里不讨论)
static 可以修饰属性 ====>> 静态变量
static 可以修饰方法 ====>> 静态方法
static 可以修饰代码块 ====>>静态代码块
-
static 修饰属性 ====>> 静态变量
static可以修饰成员变量,不能修饰局部变量
public class Student { String stuID; String name; static String clsName; //static 修饰成员变量 }
public class TestStudent {
public static void main(String[] args) { Student s1 = new Student(); s1.stuID="sg1524163"; s1.name="刘备"; s1.clsName="蜀国一班";//一处设置处处设置,一处修改处处修改! Student s2 = new Student(); s2.stuID="sg16556163"; s2.name="关羽"; //s2.clsName="蜀国一班"; Student s3 = new Student(); s3.stuID="sg16657463"; s3.name="张飞"; //s3.clsName="蜀国一班"; //当遇到很多对象都有同一个属性的值时,可用static修饰这个属性来减少赋值 System.out.println(s1.name+"\t"+s1.clsName); System.out.println(s2.name+"\t"+s2.clsName); System.out.println(s3.name+"\t"+s3.clsName); }
}
输出结果:
刘备 蜀国一班
关羽 蜀国一班
张飞 蜀国一班
需注意的问题
上面的例子中,是用对象(s1、s2、s3) 去调用静态属性(clsName) 的。--> clsName
但是,建议用类去调用。--> Student.clsName
当成员变量声明时使用了 static 关键字,那么这种变量称为静态变量,没有使用 static 关键字称为实例变量。
实例变量必须先创建对象,通过“引用”去访问,而静态变量访问时不需要创建对象,直接通过“类名”访问。
public class Phone { int memory; static String name; } //测试类 package test; public class TestPhone { public static void main(String[] args) { Phone p1 = new Phone(); p1.memory = 128; //通过”引用“访问 //p1.name = "红米"; Phone.name = "红米"; //通过”类名“访问 System.out.println("内存:"+p1.memory); System.out.println("品牌:"+Phone.name); } }
输出结果:
内存:128
品牌:红米
静态变量总结:
所有实例相关的,包括实例变量和实例方法,必须先创建对象,然后通过“引用”的方式去访问,如果空引用访问实例相关的成员,必然会出现空指针异常。所有静态相关的,包括静态变量和静态方法,直接使用“类名”去访问。虽然静态相关的成员也能使用“引用”去访问,但这种方式并不被主张。
-
static修饰方法 ====>> 静态方法
被static关键字所修饰的方法就是静态方法。
比如我们import的util包,全是工具类!工具类所有的方法都是静态方法!
使用方法:类名 . 静态方法
下面,我们自定义一个工具类(所有方法用 static 修饰)
package cn.bjpowernode.javase01.day11.static02; public class PrintUtil { //打印长方形 public static void rect(int a,int b){ for(int i=1;i<=a;i++){ for(int j=1;j<=b;j++){ System.out.print("* "); } System.out.println(); } } //打印等腰三角形 public static void triangle(int a){ for(int i=1;i<=a;i++){ for(int j=1;j<=(a-i);j++){ System.out.print(" "); } for(int z=1;z<=(2*i-1);z++){ System.out.print("*"); } System.out.println(); } } }
创建测试类去调用上面的工具类(类名 . 静态方法)
package cn.bjpowernode.javase01.day11.static02; public class Test { public static void main(String[] args) { PrintUtil.rect(5,10); PrintUtil.triangle(5); } }
//结果如下:
-
static 可以修饰代码块 ====>>静态代码块
先看格式:
在 { } 内,除了明显的死循环,其他内容都可以写,跟方法体没什么区别
但是,静态代码块儿只能调用静态的成员,非静态代码块什么都能调用!
package test; public class Student { String name; static String clsName; //静态变量 public static void fun1(){ //静态方法 System.out.println("fun1..."); }
public void fun2(){ System.out.println("fun2..."); }
public Student() { System.out.println("Student的构造函数..."); }
static{ System.out.println("Student的静态代码块。。。"); }
{ System.out.println("Student的非静态代码块..."); } }
创建测试类
package test; public class TestStudent { public static void main(String[] args) { System.out.println("main...."); Student s1 = new Student(); Student s2 = new Student(); System.out.println("姓名:"+s1.name); System.out.println("班级:"+Student.clsName); //类.静态变量 Student.fun1(); //类.静态方法 s1.fun2(); } static{ System.out.println("TestStudent的静态代码块。。。"); } { System.out.println("TestStudent的非静态代码块..."); } }
1 执行结果: 2 TestStudent的静态代码块。。。 3 main.... 4 Student的静态代码块。。。 5 Student的非静态代码块... 6 Student的构造函数.... 7 Student的非静态代码块... 8 Student的构造函数.... 9 姓名:null 10 班级:null 11 fun1... 12 fun2...
输出结果的解释如下:
一个类中有静态代码块、非静态代码块、构造函数时,如果创建对象,执行顺序:静态代码块 ==> 非静态代码块 ==> 构造函数
如下图:方法区中有个静态区,用来存放静态代码块、静态的变量、方法;而堆区就存放非静态的。
当运行TestStudent 类时,
第一步:编译把 *.java 文件变成 *.class 文件
第二步:类加载( ClassLoader ),把代码片段加载到 jvm 虚拟机的方法区!
类加载如果遇到静态代码块,直接执行!所以输出行2(仅一次)
当创建了对象s1,就会加载Student类,在堆中开辟0x112位置,所以输出行4(仅一次)、5、6
当创建了对象s2,在堆中开辟0x234位置,所以输出行7(同5)、8(同6)
即,如果多次创建对象,非静态代码块和构造函数执行多次,静态代码块只执行一次!
静态代码块只在类加载时执行,而类加载只会加载一次!
第三步:执行程序
jvm打开,执行程序,jvm关闭!