Static修饰符
Static修饰符
个人总结:static有五种使用场景,在这篇博客当中我会详细的介绍.
修饰静态属性
属性的分类:
静态属性:
类加载的时候初始化,而且只有一次
经典应用:产生唯一性自增ID、单例模式
初始化时机:类加载的时候
非静态属性:
类创建对象的初始化,可以初始化多次
初始化时机:调用构造方法创建对象的时候
我们通过产生唯一性自增ID的代码来理解下静态属性的特点,首先我们先来看一个代码demo01:
public class StaticField {
//非静态属性
private int id;
//构造方法
public StaticField() {
++id
}
public static void main(String[] args) {
StaticField s1 = new StaticField();
StaticField s2 = new StaticField();
System.out.println(s1.id);
System.out.println(s2.id);
}
}
结果: 1 1
如果你认为结果是s1=1,s2=2那么是错误的,通过上面的结果我们可以得出两个结论:
1.非静态属性访问方式,先创建对象,再访问(demo01中的id属性)
2.非静态属性初始化的时机是当调用构造方法创建对象时,如果多次调用构造方法
public StaticField() { ++id }则非静态属性值会重新赋值(重置),并不会叠加.
通过demo01我们了解到非静态属性的结论后,我们现在来看看代码demo02:
public class StaticField {
//非静态属性
private int id;
//静态属性
private static int guid;
//构造方法啊
public StaticField() {
this.id = guid++;
}
public static void main(String[] args) {
//静态属性访问方式,类名.属性名
//注意:如果访问的静态属性就是本类中则类名可以省略
System.out.println(StaticField.guid);
System.out.println(guid);
//非静态属性方法,先创建对象再访问
StaticField s1 = new StaticField();
StaticField s2 = new StaticField();
System.out.println(s1.id);
System.out.println(s2.id);
}
}
结果: 1 2
在demo02当中我新定义了一个静态属性guid我的目的是希望能实现产生唯一性自增ID,结果也达到了我的预期,那么通过demo02我们可以得出的结论有:
1.静态属性访问方式,类名.属性名(demo02中的guid属性)
2.非静态属性方法,先创建对象再访问(denmo02中的id属性)
3.静态属性初始化的时机是类加载的时候,而且只执行一次,即不会重置
public StaticField() { this.id = ++guid; }既然guid不会被重置,所以每一次创建对象的时候都会使它++guid自增,那么id也会对应的被guid赋值,从而间接的达到了产生唯一性自增ID的效果
修饰静态方法
方法分类:
非静态方法
非静态方法可以直接调用任何方法
静态方法:
静态方法只能直接调用静态方法,调用非静态方法前需要创建对象
demo03
public class StaticMethod {
public static void main(String[] args) {
method2();
StaticMethod demo = new StaticMethod();
demo.method1();
}
public void method1() {
}
public static void method2() {
}
}
通过demo03的代码我们可以得出如下结论:
静态方法可以直接通过类名.方法名方式调用,例如:Math.max(3,4)
非静态方法不能直接通过类名调用,它必须创建对象,然后再调用.
静态方法可以直接调用其他静态方法,但是不能直接调用非静态方法,调用非静态方法必须创建对象,然后再调用.比如说mian方法就是典型的例子
非静态方法可以直接调用静态方法或者非静态方法
修饰静态代码块
代码块分类:
非静态代码块:
会在每次构造方法调用之前优先执行调用
静态代码块:
在类加载的时候就执行并且只执行一次
使用场景:一般做系统的初始化工作,例如:建立数据库连接,加载大型资源配置文件...
初始化时机:类加载的时候
demo04:
public class StaticBlock {
{
System.out.println("普通代码块...");
}
static{
System.out.println("静态代码块...");
}
public StaticBlock() {
System.out.println("StaticBlock的构造方法...");
}
public static void main(String[] args) {
StaticBlock staticBlock1 = new StaticBlock();
StaticBlock staticBlock2 = new StaticBlock();
}
}
结果:
静态代码块...
普通代码块...
StaticBlock的构造方法...
普通代码块...
StaticBlock的构造方法...
通过demo4我们可以得出以下结论:
1,
普通代码块,调用的时机是每次调用构造方法创建对象之前都会自动优先调用(一次或者多次)
注意⚠️: 普通代码块一般不使用,因为普通代码块中的代码可以直接整合到构造方法即可
静态代码块,当类加载的时候就执行,而且有且只有一次
注意⚠️: 静态代码块非常有用!我们可以利用它来完成很多费事费力,需要消耗大量系统资源的操作(前置完成)
例如: 建立数据库连接池,建立数据库连接,加载大型资源配置文件....
修饰静态类
静态内部类
非静态内部类依赖于外部类的实例,而静态内部类不需要。
public class OuterClass {
class InnerClass {
}
static class StaticInnerClass {
}
public static void main(String[] args) {
// InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
OuterClass outerClass = new OuterClass();
InnerClass innerClass = outerClass.new InnerClass();
StaticInnerClass staticInnerClass = new StaticInnerClass();
}
}
静态内部类不能访问外部类的非静态的变量和方法。
修饰静态导入
静态导入
例如:import static xxx.xxx.xxx.*注意.*指定的是导入这个类下的所有静态方法
这样在业务开发的时候可以简化代码.
初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。
public static String staticField = "静态变量";
static {
System.out.println("静态语句块");
}
public String field = "实例变量";
{
System.out.println("普通语句块");
}
最后才是构造函数的初始化。
public InitialOrderTest() {
System.out.println("构造函数");
}
存在继承的情况下,初始化顺序为:
父类(静态变量、静态语句块)
子类(静态变量、静态语句块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)

浙公网安备 33010602011771号