目录
关键字 static
1. 修饰变量
2. 修饰方法
3. 修饰代码块
4. 修饰类
关键字 static
作用:
- 修饰类属性(变量)
- 修饰类方法
- 静态代码块
- 修饰类
1. 修饰变量
Java 中的静态变量和类相关, 和具体的实例无关。
代码示例:
class TestDemo {
public int a;
public static int count;
}
public class Demo1 {
public static void main(String[] args) {
TestDemo t1 = new TestDemo();
t1.a++;
TestDemo.count++;
System.out.println(t1.a);
System.out.println(TestDemo.count);
System.out.println("============");
TestDemo t2 = new TestDemo();
t2.a++;
TestDemo.count++;
System.out.println(t2.a);
System.out.println(TestDemo.count);
}
}
从上面代码可以看出 count 被 static 所修饰,同一个类的不同实例共用同一个静态属性。且不属于对象,访问方式为:类名 . 属性。
小结:
- static 修饰的变量称为类的静态变量或类属性(类变量),直接使用类名称来访问。
- 所有的静态变量、常量在方法区中存储。
- 常量一旦使用 static 修饰,就无法修改,修饰常量 static 一般与 final 搭配使用。
例题:
假设 A 类有如下定义,设 a 是 A 类的一个实例,下列语句调用哪个是错误的?()
public class A
{
public int i;
static String s;
void method1(){}
static void method2(){}
}
A System.out.println(a.i);
B a.method1();
C A.method1();
D A.method2();
正确答案: C
A选项可以通过实例化对象调用成员变量,正确。B选项可以通过实例化对象调用成员方法,正确。static关键词修饰的变量或方法可以通过类名直接调用,而非静态的变量或方法无法通过类名直接调用。 C选项错,D选项对。
2. 修饰方法
类中使用 static 修饰方法称为静态方法,与对象无关。
代码示例:
class TestDemo2 {
public int a;
public static int count;
public static void change() {
count = 100;
//a = 10; error 不可以访问非静态数据成员
}
}
public class Demo2 {
public static void main(String[] args) {
TestDemo2.change(); // 无需创建实例对象 就可以调用
System.out.println(TestDemo.count);
}
}
小结:
- 静态方法属于类,而不属于类的对象。
- 可以直接调用静态方法,而无需创建类的实例。
- 静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
- 在成员方法中可以调用静态方法,但是在静态方法中不能直接调用成员方法(变量),调用成员方法需要实例化对象。
- java 中无法从静态上下文中引用非静态方法。
- main 方法为 static 方法。
例题:
观察下面代码,分析内存布局。
class Person {
public int age; // 实例变量 存放在对象内
public String name;// 实例变量
public String sex;// 实例变量
public static int count;// 类变量也叫静态变量,编译时已经产生,属于类本身,且只有一份。存放在方法区
public final int SIZE = 10;// 被final修饰的叫常量,也属于对象。 被final修饰,后续不可更改
public static final int COUNT = 99;// 静态的常量,属于类本身,只有一份 被final修饰,后续不可更改
// 实例成员函数
public void eat() {
int a = 10;//局部变量
System.out.println("eat()!");
}
// 实例成员函数
public void sleep() {
System.out.println("sleep()!");
}
// 静态成员函数
public static void staticTest() {
// 不能访问非静态成员
// sex = "man"; error
System.out.println("StaticTest()");
}
}
public class Demo3 {
public static void main(String[] args) {
// 产生对象 实例化对象
Person person = new Person();// person为对象的引用
System.out.println(person.age);// 默认值为0
System.out.println(person.name);// 默认值为null
//System.out.println(person.count);// 会有警告!
// 正确访问方式:
System.out.println(Person.count);
System.out.println(Person.COUNT);
Person.staticTest();
// 总结:所有被static所修饰的方法或者属性,全部不依赖于对象。
person.eat();
person.sleep();
}
}
内存布局:
成员变量是在类中定义,类是 new 出来的,是存储到堆中的。成员变量与具体的对象有关,所以 person 对象有对应的成员变量存放在堆上;同样 person2 也是如此。count 和 COUNT 都是静态变量,存放在方法区中。person 和 person2 是方法中的变量(局部变量)存放在栈中。关于JVM的各个区详细的可以看这篇。
成员变量是存放在堆中的,局部变量是存放在栈中的。
3. 修饰代码块
定义在类中,使用 static 修饰的代码块称为静态代码块,一般用来初始化静态成员属性。
class Person2 {
private String name; // 实例成员变量
private int age;
private String sex;
private static int count = 0; // 静态成员变量
public Person2() {
System.out.println("构造方法");
}
// 实例代码块
{
this.name = "lisi";
this.age = 12;
this.sex = "man";
System.out.println("普通代码块");
}
// 静态代码块
static {
count = 10; // 只能访问静态数据成员
System.out.println("静态代码块");
}
public void show() {
System.out.println("name: " + name + " age: " + age + " sex: " + sex);
}
}
public class Demo4 {
public static void main(String[] args) {
Person2 p1 = new Person2();
Person2 p2 = new Person2();
p1.show();
}
}
运行结果:
小结:
- 在类中静态代码块最先执行,与对象无关。
- 静态代码块执行完毕后,普通代码块(构造块)执行,再然后是构造函数执行。
- 当类加载时调用静态代码块,并且当该类被加载后,只调用一次静态代码块,也就是无论生成多少个对象,静态代码块只会执行一次。
4. 修饰类
定义在外部类中的内部使用 static 修饰就是静态内部类。
内部类:嵌套在其他类内部的类。根据出现的位置和关键字,分为以下四种内部类:成员内部类、静态内部类、方法内部类、匿名内部类。
代码示例:
public class StaticInnerClass {
int age;
static int a;
// 静态类
static class Inner {
private String name;
public void test() {
System.out.println(a);
// System.out.println(age);
}
}
// 成员方法
public void fun() {
Inner inner = new Inner();
}
}
class Test {
public static void main(String[] args) {
StaticInnerClass.Inner inner = new StaticInnerClass.Inner();
}
}
小结:
- 静态内部类不能访问外部类对象。
- 静态内部类不能访问外部类的成员域,可以访问外部类的静态域。
- 静态内部类有自己的成员域。
- 在外部类的外部创建静态内部类的语法:外部类名称.Inner = new 外部类.Inner();



