static关键字:在 Java 中,static 表示“全局”或者“静态”的意思,用来修饰成员变量
、成员方法
以及代码块
。
1. static变量:
static 修饰的变量称为静态变量,没有用 static 修饰的变量称为实例变量。静态变量不依赖于实例对象存在,在内存中只有一份。
2. static方法:
static 修饰的方法称为静态方法,通过类名直接调用。静态方法在类加载的时候就存在,它不依赖于任何实例且不能是抽象方法(abstract method)。
3. static 代码块
被 static 修饰的代码块称为静态代码块,静态代码块会随着类的加载一块执行,它可以存在于该类的任何地方。
模拟Math类(除静态代码块部分,余下代码均copy自jdk源码):
- Math类被final关键字修饰,表示该类为最终类,不能被继承。
- 私有构造函数,表示Math类不能被实例化。(Do not let anyone instantiate this class. 不能让任何人实例化这个类,即使你有钱,有权,长相俊美也不行)
- 相对于jdk而言,Math类中的所有方法均为静态方法。
public final class Math {
// 静态变量
public static final double PI = 3.14159265358979323846;
/**
* Don't let anyone instantiate this class.
*/
private Math() {} // 私有构造函数,即Math类不能被实例化。
// 静态方法
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
// 静态代码块
static {
System.out.println("静态代码块");
}
}
测试代码:
public class MainClass {
public static void main(String[] args) {
// 调用静态变量
System.out.println("PI: " + Math.PI);
// 调用静态方法
int res = Math.max(8, 6);
System.out.println("max: " + res);
}
}
测试结果:
PI: 3.141592653589793
静态代码块
max: 8
例题1:通过this
访问静态变量。
public class MainClass {
private static int v = 10; // 静态变量
public static void main(String[] args) {
new MainClass().print(); // this表示当前实例对象
}
public void print() {
// The value of the local variable v is not used
int v = 20; // 局部变量
// The static field MainClass.v should be accessed in a static way
System.out.println("value: " + this.v); // this访问静态变量
}
}
测试结果:
value: 10
例题2:构造函数、(静态)代码块的执行顺序。
(一)
public class Base {
public Base() {
System.out.println("Base 构造函数");
}
// 代码块
{
System.out.println("Base 代码块");
}
}
public class MainClass extends Base {
public MainClass() {
System.out.println("MainClass 构造函数");
}
// 代码块
{
System.out.println("MainClass 代码块");
}
public static void main(String[] args) {
new MainClass();
}
}
测试结果:
Base 代码块
Base 构造函数
MainClass 代码块
MainClass 构造函数
(二)
public class Base {
public Base() {
System.out.println("Base 构造函数");
}
// 静态代码块
static {
System.out.println("Base 静态代码块");
}
}
public class MainClass extends Base {
public MainClass() {
System.out.println("MainClass 构造函数");
}
// 静态代码块
static {
System.out.println("MainClass 静态代码块");
}
public static void main(String[] args) {
new MainClass();
}
}
测试结果:
Base 静态代码块
MainClass 静态代码块
Base 构造函数
MainClass 构造函数
(三)
public class User {
public User() {
System.out.println("User 构造函数");
}
// 静态代码块
static {
System.out.println("User 静态代码块");
}
}
public class MainClass extends Base {
public MainClass() {
System.out.println("MainClass 构造函数");
}
// 静态代码块
static {
System.out.println("MainClass 静态代码块");
}
}
public class Base {
// 成员变量
public User user = new User();
public Base() {
System.out.println("Base 构造函数");
}
// 静态代码块
static {
System.out.println("Base 静态代码块");
}
// main方法
public static void main(String[] args) {
System.out.println("main方法");
new MainClass();
}
}
测试结果:
Base 静态代码块
main方法
MainClass 静态代码块
User 静态代码块
User 构造函数
Base 构造函数
MainClass 构造函数
执行结果分析:
- 在Java中,main(String[] args)方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main(String[] args)方法。但是,在(三)中,执行main(String[] args)方法之前需要加载Base类,如果类中有静态代码块,则首先执行静态代码块,于是打印出“Base 静态代码块”。
- Base类加载完成之后(Base类中的
静态代码块
已经执行完成),开始执行main(String[] args)方法,于是打印出“main方法”。 - 在main(String[] args)方法中执行“new MainClass();”语句对MainClass类进行实例化,在实例化MainClass类之前需要加载MainClass类,如果类中有静态代码块,则首先执行静态代码块,于是打印出“MainClass 静态代码块”。
- 因为Base类是MainClass类的父类,所以实例化MainClass类之前将首先需要初始化Base类(父类)的成员变量,再调用Base类(父类)的构造函数。初始化Base类(父类)的成员变量就必须先加载User类,如果类(User类)中有静态代码块,则首先执行静态代码块,于是打印出“User 静态代码块”。
- 在User类加载完成之后(User类中的
静态代码块
已经执行完成),将调用User类的构造方法,于是打印出“User 构造函数”。 - User类的构造方法执行完成,即Base类中的成员变量初始化完成,则调用Base类的构造方法,于是打印出“Base 构造函数”。
- Base类的构造方法执行完成,即父类的构造方法执行完成之后再调用子类(MainClass类)的构造方法,于是打印出“MainClass 构造函数”,进而生成MainClass实例对象。
(四)
public class MainClass {
// 静态代码块
static {
System.out.println("MainClass 静态代码块1");
}
// main函数
public static void main(String[] args) {
}
// 静态代码块
static {
System.out.println("MainClass 静态代码块2");
}
}
测试结果:
MainClass 静态代码块1
MainClass 静态代码块2
官方文档:
http://docs.oracle.com/javase/8/docs/api/index.html
参考网址:
http://www.cnblogs.com/dolphin0520/p/3799052.html