static关键字的用法
static 可以用来修饰属性,方法,代码块
1、静态属性
定义
使用static关键字修饰的属性就是静态属性
如:
static int num;
1.1 用法
(1)可以直接使用类名来访问(推荐)
(2)也可以使用对象访问
代码案例如下:
public class Demo{
static int num;
}
public static void main(String[] args){
Demo.num = 10; //通过类名访问
Demo demo = new Demo();
demo.num = 20; //通过对象来访问
}
1.2 基本特点
1、静态属性可以使用类名或者对象来访问
2、静态属性是属于类的,是这个类的所有对象所共享的
1.3 存储位置
存储在内存中的方法区
1.4 静态属性与非静态属性的初始化
要么系统默认赋值,要么人为手动赋值。
初始化时间:
(1)静态属性:
类加载到内存中(方法区)的时候,系统会给类中的静态属性做初始化赋默认值,所以在没有创建对象的时候,只要类加载到了内存就可以直接使用类名来访问静态属性。
(2)非静态属性:
创建对象后,系统自动给对象中的非静态属性做初始化赋默认值,所以对于非静态属性,只有在创建对象后才能通过对象访问。
注意:
1、Demo类,被加载到内存的时候,静态属性num已经完成了默认的初始化赋值操作
2、可以通过类名(Demo.num)来访问,它可以直接找到方法区中存储的静态变量num
3、可以通过对象(demo.num)来访问,引用demo先找到堆区中的对象,再根据对象中存储的Demo.class信息,找到方法区中存储的静态变量num
4、通过上述可知,无论使用类名还是使用对象来访问静态变量num,都是访问的同一个num,但是官方推荐的是使用类名来访问更加合适。
小结:
静态属性是属于类的,只要类加载到内存了,就可以使用类名来访问。
非静态属性是属于对象的,只有创建出对象了,使用对象才可以访问
2、静态方法
2.1 定义
使用static修饰的方法
2.2 静态方法的调用
(1)使用类名调用(推荐)
(2)使用对象来调用
代码演示:
public class Demo{
public static void test(){
}
}
public static void main(String[] args){
Demo.test();//推荐的方式
Demo demo = new Demo();
demo.test();//可以调用,但是不推荐
}
注意
1、静态方法中不能调用类中的非静态方法或非静态属性
2、在非静态方法中可以直接访问类中的静态属性和静态方法
3、在构造器中对类中的静态属性做初始化编译时可以通过的,但运行时候可能会出现问题
补充
1、在类加载的时候,JVM会优先给类中的静态属性做初始化,给类中的静态方法分配内存空间。
2、而类中非静态属性的初始化,非静态方法的分配空间,是要等到创建对象之后才会进行的。
3、所以类加载完成之后,就可以直接使用类名访问静态属性和静态方法。
4、所以创建对象之后,才可以使用对象访问非静态属性和调用非静态方法。
??问题??
有如下代码:虽然在构造器中给num赋值为10,但是在访问num的时候,看到的结果却是0
public class Demo {
public static int num;
public Demo(){
num = 10;
}
}
public static void main(String[] args){
System.out.println(Demo.num);//输出结果为 0
}
原因:
构造器是在创建对象的时候调用的,而在上面的代码中,我们并没有创建对象,而是直接使用类名访问了这个num属性,那么构造器中的代码也就没有执行,所以最后看到的结果是0。
3、静态代码块
3.1 定义
静态代码块,也叫做静态初始化代码块,它的作用就是给类中的静态属性做初始化的
3.2 静态代码块的执行时刻
类加载的时候自动执行,可以更早的给类中的静态属性,进行初始化赋值操作。并且,静态代码块只会自动被执行一次,因为JVM在一次运行中,对一个类只会加载一次
3.3 关于匿名代码块
3.3.1 作用
给非静态属性做初始化操作。
代码演示如下
public class Demo {
public int num;
//匿名代码块
{
num = 10;
}
}
public static void main(String[] args){
Demo demo = new Demo();
System.out.println(demo.num);//输出结果为 10
}
类中的构造器,既能给非静态属性进行初始化,又能配合new关键字进行对象的创建,所以匿名代码块使用的场景较少,它能完成的工作,使用构造器也一样可以完成。
3.3.2 匿名代码块的执行时刻
由于匿名代码块没有名字,我们并不能主动调用,它会在创建对象的时候,构造器执行之前,自动执行。并且每次创建对象之前,匿名代码块都会被自动执行。
— 题目 ----分析如下代码—
public class Test {
public static void main(String[] args) {
Zi z = new Zi();
}
}
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("匿名代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("匿名代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
//结果:
静态代码块Fu
静态代码块Zi
匿名代码块Fu
构造方法Fu
匿名代码块Zi
构造方法Zi
分析:
(1)类加载到内存中的时候,静态代码块就会执行,所以先执行完所有静态代码块,但注意,如果有子父类关系,就先执行父类,再执行子类。所以先执行两个静态代码块,且执行一次。
(2)匿名代码块在创建对象的时候,构造方法之前执行,也是按先父类再子类的顺序,所以先执行父类的匿名代码块,在执行父类中的构造方法,接下来才是子类中的匿名代码块,构造方法。
4、静态导入
定义
在自己的类中,要使用另一个类中的静态属性和静态方法,那么可以进行静态导入,导入完成后,可以直接使用这个类中的静态属性和静态方法,而不用在前面加上类名。
使用静态导入与非静态导入对比
//静态导入
import static java.lang.Math.PI;
import static java.lang.Math.random;
public class Demo {
public void test(){
System.out.println(PI);
System.out.println(random());
}
}
//非静态导入
public class Demo {
public void test(){
System.out.println(Math.PI);
//访问Math类中的静态属性PI,表示圆周率π
System.out.println(Math.random());
//访问Math类中的静态方法random(),生成随机数
}
}