通常情况下, 类成员需要通过它的类的对象访问,如果一个成员被声明为static,它能够在它的类的任何对象创建之前被访问, 而不用引用任何对象。
声明为static的一个类变量或方法,所有的该类的实例都会共享这个static变量或方法。

static

static修饰变量

静态变量在内存中只有一份, jvm只为静态变量分配一次内存,随着类的加载而加载到静态方法区内存中。由于静态变量属于类,和类的实例无关, 所以可以直接通过类名进行访问。

对于成员变量,每创建一个该类的实例就会创建该成员变量的一个拷贝,分配一次内存,由于成员变量是和类的实例绑定的,所以不能直接通过类名对它进行访问。

static修饰方法

  • 只能调用其他的static方法
  • 只能访问static数据
  • 不能以任何方式引用thissuper

静态方法可以直接通过类名调用, 任何该类的实例也可以调用它的静态方法, 所以静态方法不能用this或者super

static 方法独立于任何实例, 所以static方法必须被实现,不能是抽象的absract,在static方法里引用任何的实例变量都是违法的。

static 修饰类

普通类不允许被声明为静态, 只有内部类才可以。被static修饰的内部类可以作为一个普通类来使用, 而不需实例一个外部类(不需要new,直接静态加载)。

内部类没有使用static关键字,不能直接创建实例。

不使用static修饰内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
public 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
12
public class OuterClass {
public static class InnerClass{
InnerClass(){}
}
}

public class TestStaticClass {
public static void main(String[] args) {
// OutClass 不需要生成实例
new OuterClass.InnerClass();
}
}

static修饰代码块

1
2
3
static {
System.out.println("test");
}

它独立于类成员,可以有多个, jvm 加载类的时候会执行这些静态代码块, 如果有static代码块多个,jvm会按照他们在类中出现的顺序执行且每个只执行一次。可以通过静态代码块对static变量进行赋值。

final

final可以修饰非抽象类, 非抽象类成员方法和变量

final修饰变量

一个变量可以声明为final, 目的是阻止它的内容被修改, 这意味着声明final变量的时候, 必须对其进行初始化,这种用法有点类似于c++的const

通常,我们会用 final定义一些常量 , 如

1
2
3
final 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同时使用

同时使用 finalstatic修饰类成员, 该类成员拥有二者特性。

1
static final int LIMIT=100; // LIMIT表示全局常量

如果是方法的话,方法可以被继承, 可以通过类名被访问, 但是不能被子类覆盖。

对于一些用finalstatic修饰的容器类型(比如,ArrayListHashMap)的实例变量,不可以改变容器变量本身,但可以修改容器中存放的对象。