static 在英文字典中两个主要的意思为:
0.showing little change -- 几乎不发生改变的;
1.standing or fixed in one place : stationary -- 静态的;
Java 很多关键从字面上理解,就能一下子反应出它的最本质作用,static也是其中一个,今天我将从以下几点阐释对static的理解:
1. 为何使用 static && 如何使用 static
2. static 隐藏陷阱
Part one : 为何使用 static && 如何使用 static
在大部分时候,当我们访问类中的成员时,我们通常会通过实例化一个对象来访问类中的成员变量或是成员函数,此时,对象object 就成为了我们触摸类的一个显示接口,这样访问类成员确实非常容易,但是只是每次访问的时候都需要创建一个实例对象,还要调用构造函数,为它开辟相应的内存空间,倘若有一些成员变量或成员函数只是完成某一定功能,或只需初始化一次就够了,那么只能通过每次创建实例对象来访问就显得有点违背空间利用率了。所以 Java 保留关键字static,并可用于修饰变量,方法,代码块。从而实现无实例快速访问功能。
下面是一个关于David 的类:
package david;
class David {
String name = "David"; //可以声明为static类型
int age;
float height;
float weight;
public David(int age, float height, float weight) //带参数的构造函数
{
this.age = age;
this.height = height;
this.weight = weight;
System.out.println("David's constructor has been called.");
}
public David(David dav) //赋值构造函数
{
this.age = dav.age;
this.height = dav.height;
this.weight = dav.weight;
System.out.println("David's constructor has been called.");
}
public void showInfo() //显示David信息函数
{
System.out.println("Info of David:");
System.out.println("name: "+name);
System.out.println("age: "+ age);
System.out.println("height: "+height);
System.out.println("weight: "+weight);
}
public static void main(String args[]) //main()函数
{
David David_age_10 = new David(10, 145,70); //10岁david对象
System.out.println("David of age 10");
David_age_10.showInfo();
David David_age_20 = new David(20,172, 120); //20岁david对象
System.out.println("David of age 20. He has grown up "
+ "with same name and higher and heavier body.");
David_age_20.showInfo();
}
}
执行结果:
David's constructor has been called.
David of age ten
Info of David:
name: David
age: 10
height: 145.0
weight: 70.0
David's constructor has been called.
David of age twenty. He has grow up with same name and higher and heavier body
Info of David:
name: David
age: 20
height: 172.0
weight:
从这个例子中,我们可以发现,不管是10岁的David还是20岁的David,他的名字David不会发生改变,而main()中创建了两次实例对象时,构造函数都初始化了类中string name成员,所以可以将name声明为static类型,一方面让JVM只在类加载时对name初始化一次,只会存在一个副本,并为该变量开辟一个特殊的固定存储空间存放,以便直接通过类名直接访问即可。而不像上面的例子中David_age_10和David_age_20中分别存在name。当然,除了修饰static外,还可以将类成员函数showInfo()也声明为static 类型。
将name声明为static !
将showInfo()声明为static!
直接通过类名访问static成员函数showInfo(),而不能通过实例对象访问static类型成员!!!
static还可以用于代码块,从而提高代码效率!!!
看下面的一个例子:
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。下面看个例子:
class Person{
private Date birthDate;
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
Date startDate = Date.valueOf("1946");
Date endDate = Date.valueOf("1964");
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf("1946");
endDate = Date.valueOf("1964");
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
Part two: static 隐藏陷阱
在使用static有一些小细节需要抠一抠:
1、它只能调用static变量。
2、它只能调用static方法。
3、不能引用super,不能将类声明为static。
4、static 静态代码块对类进行初始化,构造函数是对对象进行初始化。
5、类加载时,static静态代码块优于main()而先被调用。
6、static关键字无法改变类中成员权限。
关于成员权限的例子:
static并没有扩充private变量的looking的权限,其对于子类仍然无法访问;