工作两年以上的coder基本上都会常常用到static关键字修饰符,比如常用的工具类中我们会经常声明一些常用的static静态方法,如在JDK中的java.lang.Math类和java.lang.System类中的所有方法都被声明成为static方法;另外在程序中的全局常量经常也被声明成为static静态成员变量,比如一些固定的公式中的指定值,如自然对数的底数e为java.lang.Math.E,还有圆周长与直径之比pi为java.lang.Math.PI等。
对于
我自己来说在实际的工作之中慢慢的能体会到在什么时候适合用static关键字,但是已经忘记了对static的真正
理解,当对有的知识已经学会运用的时候,这个时候去反思为什么用,为什么这么用,在有实践的基础再去深入的理解
他们我想会有更大的收获,你也许会体会到对于这些语言从整体上看前辈为什么会这样设计,出于什么目的以及他们的设计思想。所以我觉得思考是很关键的,用自己的脑子去思考……
static声明的有静态方法、静态成员变量、静态块、以及静态类,静态方法和静态成员变量又分别叫做类方法和类成员变量,试想为何在之前加一个“类”字?我们常用的成员变量和方法真正并不属于类,而是属于实例化的某个类对象,且每个实例化对象都有属于自己的成员变量。可见类方法和类成员变量并非属于特定的对象且特定的对象是在运行期间生成的,而它是属于类级别的在类被装载到
内存的时候就被初始化了,跟实例化没有任何关系。被装载到的内存区域是一块专门存放静态变量的内存区域,可以叫做静态域,在《Thinking in Java》中对静态域叫做静态存储,是这样描述的:
静态存储。这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。
可以通过以下代码测试静态方法、静态成员变量、静态块、以及静态类的加载顺序:
public class StaticTest {
private String str = "hello world";
// 静态成员变量
private static String str2 = "hello";
// 静态块
static {
new StaticClass("test");
}
//静态块
static {
System.out.println(str2);
}
// 静态类
static class StaticClass {
public StaticClass(String str) {
System.out.println(str);
}
}
private static String toSay(String str){
return str;
}
public static void main(String[] args) {
System.out.println(StaticTest.toSay("word"));
StaticTest test = new StaticTest();
System.out.println(test.str);
}
}
?执行结果:
test
hello
word
hello world
可见在运行main主方法后,在调用System.out.println(StaticTest.toSay("word"));时就已经打印了test和hello,说明在类被加载到内存就已经执行了静态块的内容,根据test和hello打印先后顺序可以判断静态块是按照在代码中的先后顺序而执行的,如果静态块中涉及到静态类,则执行静态类的构造方法,然后才是执行main方法里的代码。
如果这一步理解到位了就能很容易的理解static了:它是类的公用全局变量或方法,对于类变量来说在类被加载时就被初始化了,始终只存在一份,存放于内存区的静态域内,跟类实例化对象没有关系,所以可以通过类名直接调用,正是因为跟实例化没有关系,所以在static方法中不能访问非静态成员(非静态成员必须依赖于实例化对象而存在),不会将对象的引用传递给它。
当真正理解了static后就能在应用中体会到它好处,首先毋庸质疑的是能很好的方便直接通过类名就能直接访问;另外通过static可以对全局变量作整体控制,维护一份static变量就能控制所有相关用到的引用;其次从内存空间角度来说在内存中只存在一份在占用内存空间和效率方面都有好处;还有是在运行期间之前可以加载一些后续业务的前提资源;但是也有人说由于static是面向类的而不是对象的,所以违背了面向对象的思想,然而事实上有经验的coder经常在使用static来
编码。