前言:
在java的关键字中,static和final是两个我们必须掌握的关键字。不同于其他关键字,他们都有多种用法,而且在一定环境下使用,可以提高程序的运行性能,优化程序的结构。我们经常见到static,例如每个main方法都会被标记为static修饰符,下面我们先来了解一下static关键字及其用法。
static关键字
一、静态域
如果将域(属性)定义为static,每个类中只有一个这样的域。而每一个对象对于所有的实例却都有自己的一份拷贝。
例如:假定需要给每一个雇员赋予唯一的标志码。这里给Employee类添加一个实例域id和一个静态域nextId。
代码示例:
class Employee{ private static int nextId = 1; private int id; ... }
现在每个雇员都有一个自己的id域,但这个类的所有实例将共享一个nextId域。换句话说,如果有1000个Employee类的对象,则有1000个实例域id,但只有一个静态域nextId 。
我们从内存看一下原因:
从内存理解可以清楚的看出static的作用,另外我们要知道,即使没有一个雇员对象,静态域nextId也已经存在。即它属于类,而不属于任何独立的对象,不属于实例。
static类型在实例化创建的时候不会新建,节省内存,但是有一个实例改变他的值,所以的实例里面都会对应修改,如果不想被修改,应该用final修饰。
二、静态常量
静态变量使用的比较少,但静态常量却使用得比较多。这里就不做赘述。
三、静态方法
静态方法是一种不能向对象实施操作的方法。静态方法可以访问自身类中的静态域。
下面我们看代码1:
package practice6; public class Employee3 { static{ System.out.println("这是静态初始化块1"); } private static int nextId = 90; private int id; private String name = "巴啦啦"; private double salary; { System.out.println("这是非静态初始化块:" + nextId + "==name:" + name); id = nextId; nextId++; } static{ System.out.println("这是静态初始化块2:" + nextId); } public Employee3(String n ,double s) { name = n; salary = s; } public Employee3() { System.out.println("这是构造方法"); name = ""; salary = 0; } }
package practice6; public class Test4 { public static void main(String[] args) { // TODO Auto-generated method stub Employee3 a = new Employee3(); } }
运行结果:
解释:
这里我们似乎可以看到,静态初始化块都先输出了,因为被static修饰,即使没有实例化对象,也已经存在,但是静态初始化块修饰的无论是什么情况下都会优先输出吗???目前的代码似乎是这个意思。
下面我们再看一下更改的代码2:
实例化一个静态方法Employee3,其他不变
package practice6; public class Employee3 { static{ System.out.println("这是静态初始化块1"); } private static int nextId = 90; private int id; private String name = "巴啦啦"; private double salary; //我们在这里实例化了一个静态Employee3方法 private static Employee3 as32 = new Employee3(); { System.out.println("这是非静态初始化块:" + nextId + "==name:" + name); id = nextId; nextId++; } static{ System.out.println("这是静态初始化块2:" + nextId); } public Employee3(String n ,double s) { name = n; salary = s; } public Employee3() { System.out.println("这是构造方法"); name = ""; salary = 0; } }
运行结果:
这里我们发现并不是所有被static修饰的都会优先输出,为什么???
解释:
首先我们看到运行结果,第一行静态初始化块1在函数的最顶部,所以优先加载出来,然后第二、三行加载的静态初始化块和构造方法,第四行开始实际是加载实例化静态方法Employee3的,由于static修饰的只会加载一次,所以static修饰的尽量会在实例化静态方法Employee3中才加载靠后输出。
下面我们再看一下更改的代码3:
在static修饰的方法里面实例化一个Employee3,其他不变
package practice6; public class Employee3 { static{ System.out.println("这是静态初始化块1"); Employee3 as = new Employee3(); //改变所在行 } private static int nextId = 90; private int id; private String name = "巴啦啦"; private double salary; private static Employee3 as32 = new Employee3(); { System.out.println("这是非静态初始化块:" + nextId + "==name:" + name); id = nextId; nextId++; } static{ System.out.println("这是静态初始化块2:" + nextId); } public Employee3(String n ,double s) { name = n; salary = s; } public Employee3() { System.out.println("这是构造方法"); name = ""; salary = 0; } }
运行结果:
解释:
这里我们只解释一下为什么第一个输出的非静态初始化块的nextId 值为0,我们明明给nextId 赋值为90了啊。
这就是受static修饰的不论被实例化多少次,只会加载一次的影响,我们是这样定义的:private static int nextId = 90; 既然nextId 被static修饰,那么执行as 方法的时候会先跳过去执行非静态方法,所以调用nextId 时,会使用nextId 的默认值,int的默认值是0。
总结
Java中static的含义和用法:
static:静态的,用于修饰成员(成员变量,成员方法);
1.被static所修饰的变量或者方法会储存在数据共享区;
2.被static修饰后的成员变量只有一份!
3.当成员被static修饰之后,就多了一种访问方式,除了可以被对象调用之外,还可以直接
被类名调用,(类名.静态成员);
4.static的特点:
a.随着类的加载而被加载;
b.优先于对象存在;
c.被所有对象共享;
5.被static修饰的变量成为静态变量(类变量)或者实例变量;
6.存放位置
a.类变量随着类的加载而存在于date内存区;
b.实例变量随着对象的建立而存在于堆内存;
7.生命周期:
a.类变量周期生命最长,随着类的消失而消失;
b.实例变量生命周期比类变量短,它是随着对象的消失而消失;
8.方法注意事项:
a.静态的方法只能访问静态的成员;
b.非静态得方法即能访问静态得成员(成员变量,成员方法)又能访问非静态得成员;
c.局部变量不能被static修饰;
d.静态得方法中是不可以定义this、super关键字的,因为静态优先于对象存在,所以静态方法不可以出this;
9.什么时候使用static修成员:
当属于同一个类的所有对象出现共享数据时,就需要将存储这个共享数据的成员用static修饰;
10.什么时候使用static修饰方法:
当功能内部没有访问到非静态的成员时(对象特有的数据)那么该功能可以定义成静态的.
注意:
- 非静态的成员变量只能使用对象进行访问,不能使用类名进行访问。
- 千万不要为了方便访问数据而使用static修饰成员变量,只有成员变量的数据是真正需要被共享的时候才使用static修饰。