刚接触 Java 时,很多人不是背不会 static 的定义,而是看见报错和运行结果时完全对不上号:明明方法写在同一个类里,为什么就是不能调?这篇文章不绕概念,先从最常见的报错和现象入手,再用变量共享、静态代码块和使用判断把 static 的边界讲清楚,帮你在写代码时判断它到底该不该加。
先看最常见的报错:为什么同一个类里也不能直接调用?
很多新手第一次接触 static,往往是从一条 IDE 报错开始的:

public class Student {
private String name;
public void sayHi() {
System.out.println("Hi, " + name);
}
public static void main(String[] args) {
sayHi(); // 直接爆红
}
}
提示通常是:
Non-static method ‘sayHi()’ cannot be referenced from a static context
这句话的重点其实只有一个:你在 static 环境里,去调用了一个必须依赖对象的方法。
main 是 static 的,程序启动时可以直接执行它,不需要先创建某个 Student 对象;但 sayHi() 是普通方法,它属于某个具体对象。编译器并不知道你想调用的是谁的 sayHi(),所以会直接拒绝。
正确写法是什么?
先创建对象,再通过对象调用方法:
public static void main(String[] args) {
Student s = new Student();
s.sayHi(); // 这样才行
}
只要把这一步想清楚,很多 related 的报错都会顺下来:static 里不是“什么都不能调”,而是不能直接调依赖对象的成员。
`static` 到底表示什么:属于类,不属于某个对象
如果只记一句话,那就是:
static是属于类的,不是属于某一个对象的。
这个定义看起来抽象,但换成更直观的理解会简单很多:
- 加了
static的成员,像班级公告栏,所有对象共享同一份 - 没加
static的成员,像每个人自己的笔记本,每个对象都有各自的数据
很多 Java 初学者卡住,并不是语法不会写,而是“类的公共信息”和“对象自己的信息”这两层概念没有分开。只要混在一起,就会在方法调用、变量修改和初始化顺序上不断踩坑。
为什么有的变量互不影响,有的改一个全变?
先看最常见的实例变量场景:

public class Student {
String name;
public Student(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Student a = new Student("小明");
Student b = new Student("小红");
a.name = "Java 小明";
System.out.println(a.name); // Java 小明
System.out.println(b.name); // 小红
}
}
为什么改了 a.name,b.name 不会跟着变?因为 name 没有加 static,它是实例变量。每创建一个对象,都会有自己单独的一份 name。
但如果把变量改成静态成员,情况就不一样了:
public class Student {
static String schoolName = "Java 大学";
String name;
public Student(String name) {
this.name = name;
}
public void show() {
System.out.println(name + " 来自 " + schoolName);
}
}
public class Main {
public static void main(String[] args) {
Student a = new Student("小明");
Student b = new Student("小红");
a.show();
b.show();
// 直接通过类名修改
Student.schoolName = "面向对象学院";
System.out.println("----- 修改后 -----");
a.show();
b.show();
}
}
输出:
小明 来自 Java 大学 小红 来自 Java 大学 ----- 修改后 ----- 小明 来自 面向对象学院 小红 来自 面向对象学院
这次两个对象看到的结果一起变了,因为 schoolName 只有一份,属于整个 Student 类。你改的不是某个对象自己的属性,而是所有对象共用的类级数据。
实际判断时怎么看?
像学校名、班级名、系统配置这类“大家共用一份”的信息,通常更适合写成 static。而学生姓名、年龄、成绩这种“每个对象各不相同”的数据,一般就应该保留为实例变量。

什么时候该加 `static`,什么时候不该加?
和其死记硬背,不如写代码前先问自己三个问题:
1. 这个成员是不是只和类本身有关?
如果某个数据或方法表达的是整个类共享的规则、配置或工具能力,通常可以考虑 static。
2. 它是不是必须依赖某个具体对象?
如果离开对象就说不清楚,比如“学生自我介绍”“打印当前姓名”,这类逻辑一般不该加 static。
3. 这个数据是不是所有对象共享?
如果共享,就更接近静态成员;如果每个对象都应该各自保存一份,就应该用实例成员。
几类常见场景
- 学校名、班级名、系统配置:通常适合
static - 学生姓名、成绩、年龄:通常不适合
static - 数学计算、工具方法:通常适合
static - 对象自己的行为,比如“自我介绍”:通常不适合
static
一句话概括就是:如果它是“类公共的”,就考虑 static;如果它是“对象私有的”,就别加。
静态代码块和几个高频问题,一次理顺
除了方法调用和变量共享,static 还有一个很容易让新手疑惑的点:为什么有些代码还没进 main 就先执行了?
public class Demo {
static {
System.out.println("静态代码块先执行");
}
public static void main(String[] args) {
System.out.println("main 方法执行");
}
}
输出:
静态代码块先执行 main 方法执行
原因在于 static {} 是静态代码块,它会在类第一次被加载时执行一次。程序运行某个类的 main、第一次使用该类的静态成员,或者第一次创建这个类的对象,都可能触发类加载。类先加载,再进入 main,所以它会先执行。
静态代码块一般用来做什么?
- 加载配置
- 初始化共享资源
- 输出类加载相关信息
入门阶段先记住这一句就够了:static {} 是类加载时执行的,不是创建对象时执行的。
再看几个最常见的问题
Q1:static 方法能不能访问非 static 变量?
不能,除非你先创建对象,再通过对象访问。
Q2:非 static 方法能不能访问 static 变量?
可以,因为静态变量属于类,对象也能访问它。
Q3:static 方法能不能用 this?
不能。this 代表当前对象,而 static 方法不依赖对象。
Q4:static 方法能不能被重写?
不能真正重写。子类里写同名 static 方法,更准确地说叫隐藏,不是多态意义上的重写。
最后再避开三个常见误区
- 误区一:认为
static方法不能调用任何方法。实际上它可以调用其他static方法,只是不能直接调用非static方法。 - 误区二:习惯性给所有方法都加
static。只要方法明显依赖对象状态,就不该这么写。 - 误区三:把
static理解成“静态、自动、固定不变”。入门时最稳妥的理解仍然是:它属于类。
很多人学 static 卡住,并不是这个知识点本身多复杂,而是刚开始学面向对象时,还没有把“类”和“对象”区分清楚。先盯住报错、运行结果和成员归属这三件事,理解会比死背定义快得多。







