在 Java 中,静态成员经常被描述为“属于类,不属于对象”。因此,很多人会产生一个疑问:

既然静态成员不属于对象,它还能参与继承吗?静态方法能不能被重写?

结论是:

  • 静态成员可以被子类访问,通常可以说被继承。

  • 静态方法不能被重写,只能被隐藏。

  • 静态字段不存在重写,子类定义同名字段时同样属于隐藏。

  • 静态成员不参与运行时多态。

  • 接口中的静态方法不会被实现类继承。

一、静态成员属于类,不属于对象

普通成员变量属于具体对象,而静态成员属于类本身。

class User {
static int count;
String name;
}

其中:

  • count 属于 User 类,所有 User 对象共享。

  • name 属于具体的 User 对象,每个对象都有独立的数据。

User user1 = new User();
User user2 = new User();

user1.name = “Tom”;
user2.name = “Jack”;

User.count = 2;

静态成员不需要创建对象就可以访问:

User.count;

虽然 Java 允许通过对象访问静态成员:

user1.count;

但这种写法不推荐,因为容易让人误以为 count 属于 user1 对象。

规范写法应当使用类名:

User.count;

二、静态方法可以被继承吗?

先看一个例子:

class Parent {
static void print() {
System.out.println(“Parent”);
}
}

class Child extends Parent {
}

此时可以通过子类名调用:

Child.print();

输出:

Parent

说明子类可以直接访问父类中可见的静态方法。

因此,在通常的 Java 语义中,可以说:

父类中可见的静态方法可以被子类继承。

不过这里的“继承”与实例方法不同。

子类只是可以通过自己的类名访问父类静态方法,并不代表静态方法具备运行时多态。

三、静态方法不能被重写

假设子类定义了一个与父类完全相同的静态方法:

class Parent {
static void print() {
System.out.println(“Parent”);
}
}

class Child extends Parent {
static void print() {
System.out.println(“Child”);
}
}

这不是方法重写,而是:

静态方法隐藏,Method Hiding。

调用时可以看到区别:

Parent.print(); // Parent
Child.print(); // Child

父类和子类分别拥有自己的静态方法,子类方法只是隐藏了父类同名方法。

四、为什么静态方法不能被重写?

方法重写的核心是动态绑定。

例如普通实例方法:

class Parent {
void print() {
System.out.println(“Parent”);
}
}

class Child extends Parent {
@Override
void print() {
System.out.println(“Child”);
}
}

调用:

Parent parent = new Child();
parent.print();

输出:

Child

虽然变量声明类型是 Parent,但对象实际类型是 Child。

JVM 会在运行时根据实际对象类型,决定调用 Child.print()。

这就是运行时多态。

静态方法不同:

class Parent {
static void print() {
System.out.println(“Parent”);
}
}

class Child extends Parent {
static void print() {
System.out.println(“Child”);
}
}

调用:

Parent parent = new Child();
parent.print();

输出:

Parent

原因是静态方法调用在编译阶段就已经确定。

编译器看到变量类型是 Parent,因此会将调用绑定到:

Parent.print();

它不会根据对象实际类型进行动态分派。

因此:

静态方法采用静态绑定,实例方法重写采用动态绑定。

五、不要使用对象调用静态方法

下面的代码虽然可以编译:

Parent parent = new Child();
parent.print();

但 print() 是静态方法,真正的调用目标由变量声明类型决定。

等价于:

Parent.print();

所以更推荐直接使用类名:

Parent.print();
Child.print();

这样可以清楚表达静态方法属于哪个类,也不会让人误以为存在多态调用。

六、静态字段可以被继承吗?

来看一个简单例子:

class Parent {
static int value = 10;
}

class Child extends Parent {
}

可以通过子类访问:

System.out.println(Child.value);

输出:

10

说明子类可以访问父类中可见的静态字段。

通常也可以说:

静态字段可以被子类继承。

不过,静态字段与静态方法一样,都不参与运行时多态。

七、静态字段不能被重写,只能被隐藏

如果子类定义同名静态字段:

class Parent {
static int value = 10;
}

class Child extends Parent {
static int value = 20;
}

此时父类和子类中存在两个不同的字段:

System.out.println(Parent.value); // 10
System.out.println(Child.value); // 20

这叫做字段隐藏,而不是字段重写。

事实上,字段本身就没有“重写”的概念。

不仅静态字段不能重写,实例字段同样不能重写。

class Parent {
int value = 10;
}

class Child extends Parent {
int value = 20;
}

调用:

Parent parent = new Child();
System.out.println(parent.value);

输出:

10

字段访问由引用变量的声明类型决定,不根据对象实际类型动态分派。

八、字段隐藏与方法重写的区别

下面这个例子可以直观看出两者差异:

class Parent {
int value = 10;

void print() {
System.out.println(“Parent”);
}
}

class Child extends Parent {
int value = 20;

@Override
void print() {
System.out.println(“Child”);
}
}

调用:

Parent parent = new Child();

System.out.println(parent.value);
parent.print();

输出:

10
Child

原因是:

  • 字段访问看引用变量的声明类型。

  • 实例方法调用看对象的实际类型。

也就是说:

成员类型

调用依据

是否支持多态

实例方法

对象实际类型

支持

静态方法

类名或引用声明类型

不支持

实例字段

引用声明类型

不支持

静态字段

类名或引用声明类型

不支持

九、访问权限会影响继承和访问

并不是父类中的所有静态成员都能被子类直接访问。

class Parent {
private static void privateMethod() {
}

static void packageMethod() {
}

protected static void protectedMethod() {
}

public static void publicMethod() {
}
}

具体规则如下:

修饰符

子类能否访问

private

不能直接访问

默认权限

同包子类可以访问

protected

子类可以访问

public

可以访问

其中,父类的 private 静态成员虽然仍然存在于父类中,但对子类不可见。

因此,严格来说:

子类只能继承和访问父类中对自己可见的成员。

十、接口中的静态方法不会被实现类继承

接口中的静态方法比较特殊。

interface Printer {
static void print() {
System.out.println(“Printer”);
}
}

class ConsolePrinter implements Printer {
}

下面的调用是错误的:

ConsolePrinter.print();

只能通过接口名调用:

Printer.print();

因此:

接口中的静态方法属于接口本身,不会被实现类继承。

接口这样设计,是为了避免实现类之间产生静态方法调用歧义。

十一、静态成员是否属于面向对象?

有人认为:

静态成员不属于对象,因此不属于面向对象。

这个说法并不准确。

静态成员确实不属于具体对象,也不参与对象级别的运行时多态,但它仍然位于 Java 的类和类型体系中。

静态成员依然可以参与:

  • 类的封装

  • 访问权限控制

  • 类之间的继承关系

  • 包和模块组织

  • 类型级别的功能抽象

因此,更准确的说法是:

静态成员属于类级别设计,而实例成员属于对象级别设计。

静态成员不参与运行时多态,不代表它完全脱离了面向对象体系。

十二、静态方法与实例方法的本质区别

静态方法属于类,可以直接通过类名调用:

Math.max(10, 20);

实例方法属于对象,必须依赖对象状态:

String text = “hello”;
text.length();

静态方法中不能直接访问实例成员:

class User {
String name;

static void printName() {
System.out.println(name); // 编译错误
}
}

因为调用静态方法时,可能根本没有创建任何 User 对象。

静态上下文中不存在明确的 this 对象,因此也不能直接使用:

this.name;

十三、常见误区

1. 静态方法可以重写

错误。

子类定义同名静态方法属于方法隐藏,不是方法重写。

2. 静态字段可以重写

错误。

字段没有重写概念,同名字段属于字段隐藏。

3. 静态方法会根据对象实际类型调用

错误。

静态方法在编译阶段绑定,由类名或引用声明类型决定。

4. 静态成员不属于对象,所以不能继承

错误。

“不属于对象”和“能否通过类继承体系访问”是两个不同概念。

5. 接口静态方法可以被实现类调用

错误。

接口静态方法只能通过接口名调用。

十四、最终结论

在 Java 中,父类中对子类可见的静态成员可以通过子类访问,因此通常可以说静态成员可以被继承。

但是需要注意:

  • 静态方法不能被重写。

  • 子类定义同名静态方法时称为方法隐藏。

  • 静态字段不存在重写。

  • 子类定义同名字段时称为字段隐藏。

  • 静态成员不参与运行时多态。

  • 静态调用在编译阶段完成绑定。

  • 接口中的静态方法不会被实现类继承。

最准确的表述是:

Java 中可见的静态成员可以被子类访问。静态方法不能被重写,子类定义同名静态方法属于方法隐藏;字段不存在重写,同名字段属于字段隐藏。静态成员属于类,不依赖具体对象,因此不参与运行时多态。