说明
Static 关键字是在编写代码的时候遇到的较难以理解的一个知识点 ,面试官也喜欢提这方面的问题。比如说主函数main的写法:

public static void main(String[] args){
}

这里为什么要用static呢?稍后再解答这个问题。

1. 静态变量

static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块。
按照是否静态对类成员变量进行分类可分两种:

  • 一种是被static修饰的变量,叫静态变量或类变量;
  • 另一种是没有被static修饰的变量,叫实例变量。
    -实例变量是绑定到类的某个特定实例的,它是不能被同一个类的不同对象所共享的。例如,创建了如下的两个对象:
class Person{
int i;
}
...
Person p1 = new Person();
Person p2 = new Person();

p1和p2是不相关的,它们存储在不同的内存位置。如图所示:

Java 静态变量类定义类 java定义静态变量的关键字_静态变量


p1.i的变化不会影响到p2.i, 反之亦然.

如果想要一个类中的所有实例都共享一个数据,就要使用静态变量,也称之为类变量

- 静态变量的定义

要声明一个静态变量,就要在这个变量的声明中加上修饰符static。静态变量能够被对象调用,也能被类直接调用。类中的常量是被该类的所有对象所共享的,如图所示:

Java 静态变量类定义类 java定义静态变量的关键字_java_02

 所以一般在需要实现以下两个功能时使用静态变量:

在对象之间共享值时
方便访问变量时

静态变量的调用

public class Person{
static int i;
}

public class Test{
public static void main(String[] args){
Person p1 = new Person();
Person p2 = new Person();

Person.i = 10;
System.out.println("p1的值为" + p1.i);
System.out.println("p2的值为" + p2.i);
}
}
输出结果:
p1的值为10;
p2的值为10;

也可以用对象名调用:

public class Person{
static int i;
}

public class Test{
public static void main(String[] args){
Person p1 = new Person();
Person p2 = new Person();

Person.i = 10;
System.out.println("p1的值为" + p1.i);
System.out.println("p2的值为" + p2.i);

p1.i = 20;
System.out.println("p1的值为" + p1.i);
System.out.println("p2的值为" + p2.i);
}
}
p1的值为10;
p2的值为10;
p1的值为20;
p2的值为20;

2.静态方法

静态方法可以直接通过类名调用,任何的实例也都可以调用。

  因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。
 

public class Person{
String name1;
static String name2;

static void talk(){
System.out.println("my name is " + name1);
System.out.println("my name is " + name2);
fun();
}

void fun(){
System.out.println("my name is " + name1);
System.out.println("my name is " + name2);
talk();
}
}

Java 静态变量类定义类 java定义静态变量的关键字_java_03


为什么在静态方法中不能调用非静态变量。我想是因为在面向对象中,调用成员变量必须是对象.成员变量,name1实际是this.name1;this指代的是调用这个函数的那个对象,但是静态函数咱们直接用类名来调用,不存在对象,因此会报错。

我们最常见的static方法就是main方法,至于为什么main方法必须是static的,现在就很清楚了。因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。

3.静态代码块

 static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,就会按照static块的顺序来执行每个static块,并且只会执行一次。
 静态代码块的用法
 

public Person{
static{
System.out.println("我是静态代码块");
}
}

public Test{
public static void main(){
System.out.println("Test");
}
}
输出结果:
我是静态代码块
Test

下面看个例子:

class Person{
    private Date birthDate;

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    boolean isBornBoomer() {
        Date startDate = Date.valueOf("1946");
        Date endDate = Date.valueOf("1964");
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和endDate两个对象,造成了空间浪费,如果改成这样效率会更好:

class Person{
    private Date birthDate;
    private static Date startDate,endDate;
    static{
        startDate = Date.valueOf("1946");
        endDate = Date.valueOf("1964");
    }

    public Person(Date birthDate) {
        this.birthDate = birthDate;
    }

    boolean isBornBoomer() {
        return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
    }
}

因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。