方便在没有创建对象的情况下来进行调用(方法/变量)。
很显然,被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
1)static方法
static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。但是在非静态成员方法中是可以访问静态成员方法/变量的.
我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
例如为了方便方法的调用,Java API中的Math类中所有的方法都是静态的,而一般类内部的static方法也是方便其它类对该方法的调用。
2)static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
所以一般在需要实现以下两个功能时使用静态变量:
在对象之间共享值时 、方便访问变量时
3) static代码块
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。
举例,有40W黑名单用户,提供一个静态判断方法,其中static初始化部分就是静态代码块:
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhangliang
* Sep 3, 2012 1:54:40 PM
*/
public class BlackFilter {
private static Map<String,String> blackphoneMap = new HashMap<String,String>();
static {
//读取配置文件,并初始化
String userDir = System.getProperty("user.dir");
String filepath =userDir+"/conf/40w.txt";
File file = new File(filepath);
try {
BufferedInputStream fis = new BufferedInputStream(
new FileInputStream(file));
BufferedReader reader = new BufferedReader(new InputStreamReader(
fis, "utf-8"), 5 * 1024 * 1024);// 用5M的缓冲读取文本文件
String line = "";
while ((line = reader.readLine()) != null)
{
String cols[] = line.split(",");
if (cols != null )
{
String phone = cols[0];
blackphoneMap.put(phone.trim(), phone);
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static boolean isblack(String phone)
{
if(blackphoneMap.containsKey(phone))
{
return true;
}
else{
return false;
}
}
public static void main(String [] args){
System.out.println(BlackFilter.isblack("8615896289760"));
}
}
4)static 内部类
Java语言允许在类中再定义类,这种在其它类内部定义的类就叫内部类。
静态内部类,定义在类中,任何方法外,用static定义;静态内部类只能访问外部类的静态成员。
生成(new)一个静态内部类不需要外部类成员,它唯一的作用就是随着类的加载(而不是随着对象的产生)而产生,以致可以用类名+静态成员名直接获得。:这是静态内部类和成员内部类的区别。静态内部类的对象可以直接生成:Outer.Inner in=new Outer.Inner();而不需要通过生成外部类对象来生成。
5)static导包
import static静态导入是JDK1.5中的新特性。一般我们导入一个类都用 import com…..ClassName;而静态导入是这样:import static com…..ClassName.*;
然后在这个类中,就可以直接用方法名调用静态方法,而不必用ClassName.方法名 的方式来调用。这种方法的好处就是可以简化一些操作,例如打印操作System.out.println(…);就可以将其写入一个静态方法print(…),在使用时直接print(…)就可以了。
下面是使用静态导入的几条原则:
你必须说import static, 不能说static import。
提防含糊不清的命名static成员。例如,如果你对Integer类和Long类执行了静态导入,引用MAX_VALUE将导致一个编译器错误,因为Integer和Long都有一个MAX_VALUE常量,并且Java不会知道你在引用哪个MAX_VALUE。
你可以在static对象引用、常量(记住,它们是static 或final)和static方法上进行静态导入。
对于变量,表示一旦给值就不可修改,并且通过类名可以访问。
对于方法,表示不可覆盖,并且可以通过类名直接访问。
对于被static和final修饰过的实例常量,实例本身不能再改变了,但对于一些容器类型(比如,ArrayList、HashMap)的实例变量,不可以改变容器变量本身,但可以修改容器中存放的对象,这一点在编程中用到很多。
运行结果:
********************************************* 关于static与final的初始化问题,参见final整理。 以上是常用static的用法,要是再深入理解,需要结合jvm模型的方法区等。参考:-------------值处理前----------
strStaticFinalVar=aaa
strStaticVar=null
intStaticFinalVar=0
integerStaticFinalVar=8
alStaticFinalVar=[]
-------------值处理后----------
strStaticFinalVar=aaa
strStaticVar=哈哈哈哈
intStaticFinalVar=0
integerStaticFinalVar=8
alStaticFinalVar=[aaa, bbb]