static 关键字可以用来修饰属性、方法和语句块等
- static 修饰变量,该变量称为类变量或静态变量,全局只有一份。
- static 修饰方法,该方法称为静态方法,可以无须和对象绑定,通过类名加点直接访问。
- 注意,static 不可以修饰构造方法。
- static 修改语句块,该块称为静态块,加载类时只执行一次。
- 不管是静态方法还是静态块,在静态的区域中外部非静态的成员不能进行访问。
static 关键字可以用来修饰属性,也就是用来修饰变量。
在类中被 static 关键字修饰的变量,我们称之为 "类变量" 或是 "静态变量"。
语法结构:在数据类型之前加上 static 关键字。
arduino
[private|public|protected] static 数据类型 变量名;
通过代码具体来看一下吧。 😀
在全局中,也就是类体中声明两个变量,如下:
ini
//成员变量
int i = 10;
//静态变量、类变量
static int j = 20;
然后,在主入口 main 方法中进行变量打印:
csharp
System.out.println(j);
System.out.println(i);
程序在编译的时候出错了,告诉我们 "无法从静态上下文中引用非静态变量 i" ,从错误的提示信息中我们可以看到,i 在 main 方法中是无法直接访问的,需要和对象绑定才可以使用;但是 j 没有问题,可以在 main 方法中直接使用。
🤔 那么要如何修改,才能使用呢?
变量 i 需要和对象绑定才能访问。
ini
System.out.println(j);
TestStatic ts = new TestStatic();
System.out.println(ts.i);
这样编译就能通过了,打印输出「20」 「10」。
接着,我们再来看一段代码,声明的 i 和 j 变量不变。
ini
TestStatic ts1 = new TestStatic();
TestStatic ts2 = new TestStatic();
System.out.println(ts1.i);
System.out.println(ts1.j);
System.out.println(ts2.i);
System.out.println(ts2.j);
创建两个 TestStatic 对象 ts1 和 ts2 ,分别调用 i 和 j ,运行结果如下:
对于这个结果我想大家应该没有问题吧。
接着,我们使用 ts1 对象调用 i 赋值 100,使用 ts2 对象调用 j 赋值 200,再来打印分别调用的 i 和 j 。
ini
ts1.i = 100;
ts2.j = 200;
System.out.println(ts1.i);
System.out.println(ts1.j);
System.out.println(ts2.i);
System.out.println(ts2.j);
运行结果如下图:
ts1.i
的值为 100,而 ts2.i
的值为 10,因为两个不同的对象,成员变量各自有一份;然而,ts1.j
和ts2.j
的值都是 200,因为静态变量 j 全局只有一份。
然后,我们在打印之前的变量 ts.i 和 j,看看结果如何?
csharp
System.out.println(j);
System.out.println(ts.i);
运行结果图:
从以上一系列的结果,我们可以总结出:
- 成员变量,每个对象各自有一份。
- 静态变量或类变量,全局只有一份。
好了,同学们在 /home/project
目录下,创建 TestStatic.java
源文件,代码如下:
ini
/**
* static 关键字修饰变量的使用
* @author 小桃子
*/
public class TestStatic{
//成员变量
int i = 10;
//静态变量、类变量
static int j = 20;
public static void main(String[] args) {
System.out.println(j);
TestStatic ts = new TestStatic();
System.out.println(ts.i);
// 创建不同的 TestStatic 对象进行变量访问
TestStatic ts1 = new TestStatic();
TestStatic ts2 = new TestStatic();
System.out.println(ts1.i);
System.out.println(ts1.j);
System.out.println(ts2.i);
System.out.println(ts2.j);
// 不同的对象对 i 和 j 进行赋值
ts1.i = 100;
ts2.j = 200;
// 打印不同对象的 i 和 j 变量
System.out.println(ts1.i);
System.out.println(ts1.j);
System.out.println(ts2.i);
System.out.println(ts2.j);
System.out.println("----");
System.out.println(j);
System.out.println(ts.i);
}
}
static 关键字修饰方法,我们称之为 "静态方法"。
其实我们一直到使用的 main 方法就是一个被 static 修饰的静态方法。
成员变量 i 不能直接在 main 方法中使用,就说明非静态成员不能在静态方法中使用。
语法结构:在方法返回类型之前加上 static 关键字。
arduino
[public|protected|private] static 返回值类型 方法名(参数列表){
方法体
}
在 /home/project
目录下,创建 TestStatic2.java
源文件,在类加入普通方法和静态方法,我们作一个对比。
类全局中还是声明成员变量 i 和静态变量 j ,进行使用。
ini
public static void method1(){
i = 1000;
j = 2000;
method2();
static int k = 40;
int k = 40;
}
public void method2(){
i = 150;
j = 231;
method1();
}
我们先来看一下编译结果,如下图:
静态方法 method1() 中,非静态的成员都不能再静态方法中进行访问;在方法中都不能再声明静态的变量。
method2() 是非静态方法,它可以访问外部的静态和非静态的成员。
我们声明静态方法,其中一个目的是,它的调用不在需要和对象进行绑定,直接可以通过类名访问。
scss
TestStatic2.method1();
new TestStatic2().method2();
TestStatic2.java
源代码如下:
ini
/**
* static 关键字修饰方法的使用
* @author 小桃子
*/
public class TestStatic2 {
int i = 10;
static int j = 20;
/**
* 静态方法中不能访问外部非静态的成员
*/
public static void method1(){
// i = 1000;
j = 2000;
// method2();
// static int k = 40;
int h = 40;
}
/**
* 非静态方法中可以访问外部静态和非静态的成员
*/
public void method2(){
i = 150;
j = 231;
method1();
}
public static void main(String[] args) {
TestStatic2.method1();
new TestStatic2().method2();
}
}
静态的方法,其实之前的用过的 String 类中的 valueOf(),包装类中有好多静态方法,如:parseInt() 等等。
static 关键字还可以修饰语句块,被 static 关键字修饰的语句块我们称之为静态块,否则称之为初始化块。
语法结构:在语句块之前加上 static 关键字。
arduino
static {
// 静态区域中不能访问外部非静态的成员
}
在 /home/project
目录下,创建 TestStatic3.java
源文件,代码如下:
csharp
/**
* static 关键字修饰语句块的使用
* @author 小桃子
*/
public class TestStatic3 {
// 类加载时只执行一次
static{
System.out.println("静态块");
}
// 每次创建对象时都会被加载
{
System.out.println("初始化块");
}
public static void main(String[] args) {
new TestStatic3();
new TestStatic3();
}
}
🌟 注意:
- 对静态块而言,只要加载该类,就会执行静态块的内容,但只会执行一次。
- 对初始化块而言,只有创建对象时,会去执行的部分,创建 n 个对象,就执行初始化块 n 次。
运行结果如下图: