通常情况下, 类成员需要通过它的类的对象访问,如果一个成员被声明为static,它能够在它的类的任何对象创建之前被访问, 而不用引用任何对象。
声明为static的一个类变量或方法,所有的该类的实例都会共享这个static变量或方法。
static
static修饰变量
静态变量在内存中只有一份, jvm只为静态变量分配一次内存,随着类的加载而加载到静态方法区内存中。由于静态变量属于类,和类的实例无关, 所以可以直接通过类名进行访问。
对于成员变量,每创建一个该类的实例就会创建该成员变量的一个拷贝,分配一次内存,由于成员变量是和类的实例绑定的,所以不能直接通过类名对它进行访问。
static修饰方法只能调用其他的static方法
只能访问static数据
不能以任何方式引用this 和super
静态方法可以直接通过类名调用, 任何该类的实例也可以调用它的静态方法, 所以静态方法不能用this或者super。static 方法独立于任何实例, 所以static方法必须被实现,不能是抽象的absract,在static方法里引用任何的实例变量都是违法的。
static 修饰类
普通类不允许被声明为静态, 只有内部类才可以。被static修饰的内部类可以作为一个普通类来使用, 而不需实例一个外部类(不需要new,直接静态加载)。
内部类没有使用static关键字,不能直接创建实例。
不使用static修饰内部类1
2
3
4
5
6
7
8
9
10
11
12
13public class OuterClass{
public class InnerClass{
InnerClass(){}
}
}
public class TestStaticClass{
public static void main(String[] args){
// OutClass需要先生成一个实例
OuterClass oc = new OuterClass();
oc.new InnerClass();
}
}
使用static修饰内部类1
2
3
4
5
6
7
8
9
10
11
12public class OuterClass{
public static class InnerClass{
InnerClass(){}
}
}
public class TestStaticClass{
public static void main(String[] args){
// OutClass 不需要生成实例
new OuterClass.InnerClass();
}
}
static修饰代码块1
2
3static {
System.out.println("test");
}
它独立于类成员,可以有多个, jvm 加载类的时候会执行这些静态代码块, 如果有static代码块多个,jvm会按照他们在类中出现的顺序执行且每个只执行一次。可以通过静态代码块对static变量进行赋值。
final
final可以修饰非抽象类, 非抽象类成员方法和变量
final修饰变量
一个变量可以声明为final, 目的是阻止它的内容被修改, 这意味着声明final变量的时候, 必须对其进行初始化,这种用法有点类似于c++的const。
通常,我们会用 final定义一些常量 , 如1
2
3final float PI=3.14
final boolean SUCCESS = true
.....按照编码约定, final变量的所有字符选择大写,final修饰的变量实际中不占用内存, 它实质上是一个常数。
final修饰方法
被final修饰的方法可以被子类继承, 但不能被子类的方法覆盖。 如果一个类不想让其子类覆盖它的某个成员方法, 就可以用 final关键字修饰该方法。final不能修饰构造方法。 由于父类中private 成员方法不能被子类覆盖, 所有由private修饰的方法默认也是final的。
使用final修饰成员方法除了不想让子类覆盖外, 还有一个原因就是高效,Java编译器在遇到final修饰的方法的时候会转入内嵌机制, 提高执行效率。内嵌机制 ,类似于c++ inline, 调用方法的时候直接将方法的主题插入到调用处, 而不用去访问类或者对象, 这样会提高50%左右效率。然而,如果方法主体比较庞大, 且多处被调用将导致主体代码膨胀, 同时也产生效率问题, 所以需要慎用。
final修饰类
final修饰的类不能被继承。
final和static同时使用
同时使用 final和static修饰类成员, 该类成员拥有二者特性。1static final int LIMIT=100; // LIMIT表示全局常量
如果是方法的话,方法可以被继承, 可以通过类名被访问, 但是不能被子类覆盖。对于一些用final和static修饰的容器类型(比如,ArrayList、HashMap)的实例变量,不可以改变容器变量本身,但可以修改容器中存放的对象。