由static修饰的变量、常量和方法被称作静态变量、静态常量和静态方法,也被称作类的静态成员。
静态成员是属于类所有的,区别于个别对象。
静态变量
Java中把共享的变量用static修饰
很多时候,不同的类之间要对同一个变量进行操作,比如一个水池,一边放水,一边出水,两个操作都会对水池中的水产生影响。此时水池中的水量,就可以认为是一个共享的变量。即static型。
创建一个水池类,创建注水和防水的方法,同时控制水量。
public class Pool {
static public int water = 0;
public void outlet() {// 放水,一次放出2个单位
if (water >= 2) {
water = water - 2;
} else {
water = 0;
}
}
public void inlet() {// 注水,一次注入3个单位
water = water + 3;
}
public static void main(String[] args) {
Pool out = new Pool();
Pool in = new Pool();
System.out.println("水池的水量:" + Pool.water);
System.out.println("水池注水两次。");
in.inlet();
in.inlet();
System.out.println("水池的水量:" + Pool.water);
System.out.println("水池放水一次。");
out.outlet();
System.out.println("水池的水量:" + Pool.water);
}
}
需注意的是:同一个类的不同实例对象,共用同一静态变量,如果一个类将其改变,另一个类静态变量也会更改。
建一个新的类,包含一个静态成员变量和一个普通成员变量
在构造方法中给两个变量赋初值,然后分别实例化两个不同的对象。
public class StaticVariable {
static int x;// 静态变量
int y;// 普通成员变量
public StaticVariable(int x, int y) {// 构造函数
this.x = x;
this.y = y;
}
public static void main(String[] args) {
StaticVariable a = new StaticVariable(1, 2);
StaticVariable b = new StaticVariable(13, 17);
System.out.println("a.x的值是 = " + a.x);
System.out.println("a.y的值是 = " + a.y);
System.out.println("b.x的值是 = " + b.x);
System.out.println("b.y的值是 = " + b.y);
}
}
运行结果
看结果发现 a.x 的值并不是我们一开始赋予的初值,而是和 b.x 是一样的。这是因为静态变量x是类中共享的,在对象 a 给 x 赋了一次之后,对象 b 又给 x 赋了一次值,被改变了。
对象a 与对象b在内存中共用同一静态变量
当类首次被加载时,静态变量就被分配到内存中,知道程序结束才会释放
静态常量
有时候,在处理问题时需要两个类共享一个数据常量。
例如,在球类中使用了PI这个常量,而在圆类中也需要这个常量。这个时候若是在两个类中都创建了PI这个常量,**由于系统会将两个不在一个类中的常量分配到不同的内存空间中去。**很大的浪费了系统资源。我了解决这个问题,可以将这个常量设置为静态的。
PI常量在内存中共享的布局图如下。
用final static 修饰一个成员变量,这个成员变量就会变成一个静态常量。如:
final static double PI =3.1415926;
创建Graphical类
将π的值赋给静态变量PI,使用PI计算圆类的面积和球类的体积
public class Graphical {
final static double PI = 3.1415926;// 创建静态常量π
public static void main(String[] args) {
double radius = 3.0;// 半径
Circular yuan = new Circular(radius);
Spherical qiu = new Spherical(radius);
}
}
class Circular {
double radius;// 半径
double area;// 面积
public Circular(double radius) {
this.radius = radius;
area = Graphical.PI * radius * radius;// 计算面积
System.out.println("圆的半径是:" + radius + ",圆的面积是:" + area);
}
}
class Spherical {
double radius;// 半径
double volume;// 体积
public Spherical(double radius) {
this.radius = radius;
volume = 4 / 3 * Graphical.PI * radius * radius * radius;// 计算体积
System.out.println("球的半径是:" + radius + ",球的体积是:" + volume);
}
}
注意:静态常量的命名字符都应该用大写。
静态方法
如果想要使用类中的成员方法,需要先将这个类进行实例化,但有些时候不想或者无法创建类的对象时,需要调用类中的方法才能够完成逻辑,此时就可以使用静态方法。
调用类的静态方法,无需创建类的对象。
语法如下:
类名.静态方法();
//不new新的对象,直接使用静态方法
public class StaticMethod {
static public void show() {//定义静态方法
System.out.println("静态方法无需实例化就可以调用");
}
public static void main(String[] args) {
StaticMethod.show();//使用类名调用静态方法
}
}
静态代码块
在类中除成员方法外,用static修饰代码区域可以称之为静态代码块。定义一块静态代码块,可以完成类的初始化操作,在类声明时就会运行。
// 语法如下:
public class StaticTest{
static{
//此处编辑执行语句
}
}
创建静态代码块,非静态代码块,构造方法,成员方法,查看代码的调用顺序
public class StaticTest {
static String name;
//静态代码块
static {
System.out.println(name + "静态代码块");
}
//非静态代码块
{
System.out.println(name+"非静态代码块");
}
public StaticTest(String a) {
name = a;
System.out.println(name + "构造方法");
}
public void method() {
System.out.println(name + "成员方法");
}
public static void main(String[] args) {
StaticTest s1;// 声明的时候就已经运行静态代码块了
StaticTest s2 = new StaticTest("s2");// new的时候才会运行构造方法
StaticTest s3 = new StaticTest("s3");
s3.method();//只有调用的时候才会运行
}
}
运行结果
注解:从运行结果可以看出
- 静态代码块由始至终只运行了一次
- 非静态代码块,每次创建对象的时候,都会在构造方法之前运行,所以在读取成员变量name的时候,只能获取到String类型的默认值null,还未被 s2 修改。
- 构造方法只有在使用new创建对象的时候才会运行。
- 成员方法只有在使用对象调用的时候才会运行。
- 因为name是static修饰的静态成员变量,在创建 s2 对象时将字符串“ s2 ”赋给了name,所以创建 s3 对象时,重新调用了类的非静态代码块,此时name的值还没有被 s3 对象改变,于是输出“ s2非静态代码块”