Static
Static有“静态的”之意。用来修饰变量和方法或是生成一个静态的代码块,在特殊情况下也可以用来修饰类。
变量
用static修饰的变量不属于类的实例,而是所有实例共享的(可以当全局变量使,但实际上java是没有全局变量的)。利用ruby中的概念可以理解为类变量和实例变量的区别。只要类被加载,JVM就能根据类名在运行时数据区的方法区内定找到他们。在内存中只会有一个拷贝,JVM只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问,当然也可以通过对象来访问(但是这是不推荐的)。
静态变量定义是必须初始化。
方法
静态方法,可以直接用类直接调用也可以用实例来调用,但是静态方法中不可以有任何实例变量或是实例方法,反过来看实例方法还是可以引用静态变量和静态方法的。Abstract不可以和static同时出现。
代码块
static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
这里需要注意的是,不同的反射加载机制对静态变量和静态代码块是有影响的。(具体见【类加载】)
l Class.forName(…),在加载时会进行初始化处理(对类的静态变量、代码块执行初始化操作)
l ClassLoader.loadClass(…),只会执行类装载器的第二步(即只会执行类正确性校验、静态变量空间分配和符号解析),那么这时将不会对静态变量、代码块进行初始化操作,则此时类中的静态代码块中的代码是不会执行的。
所以在连接数据库时,必须通过
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
来加载驱动,而不能是ClassLoader.loadClass(…),就是这个原因。
类
我们有时使用内部类是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类的对象。为此,就可以把内部类声明为static,以便取消产生的引用。
比如我们的内部类的对象是在静态方法中构造的,那么必须使用静态内部类。与普通内部类的区别在于静态内部类没有对生成它的外围类对象的引用特权。
使用static的情况
在我们创建一个类的实例时(对象),通常使用new方法,这样这个类的数据空间才会被创建,其方法才能被调用。
但是,有时候我们希望一个类虽然可以被创建n个对象(显然这n个对象的数据空间是不相同的),但这n个对象的某些数据是相同的,即不管这个类有多少的实例,这些数据对这些实例而言之有一份内存拷贝(见示例1)。这是静态变量的情形。
另一种情形是,你希望某个方法不与包含它的类的任何对象关联在一起。也就是说,即使没有创建对象,也能够调用这个方法。static 方法的一个重要用法就是在不创建任何对象的前提下,就可以调用它。这是静态方法的情形。
还有一种特殊的用法出现在内部类中,通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。这是静态类的情形。