gpt4 book ai didi

java - 当通过派生类引用调用基类的静态方法时,哪些类会被初始化?

转载 作者:太空宇宙 更新时间:2023-11-04 10:44:08 24 4
gpt4 key购买 nike

我认为调用 Derived.f() 时只有基类被初始化。 就像当我们在 Base 中有一个(非编译时常量)静态字段而不是静态方法时发生的情况一样。我的疑问只是 JLS 对此不太清楚。

class Base {
static void f() {}
}

class Derived extends Base {

}

Derived.f(); // called legally from some other class

根据JLS(见下文),似乎只有基类被初始化。但是我正确地阅读和理解了JLS吗?

我还知道,在使用(非编译时常数)静态字段的情况下,只有定义静态字段的类才会被初始化(调用静态初始化器):

class Base {
static int x = 1;
}

class Derived extends Base {

}

//somewhere in some other class
int y = Derived.x; // triggers only Base to be initialized

12.4.1. When Initialization Occurs (JLS)

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

T is a class and an instance of T is created.

T is a class and a static method declared by T is invoked.

A static field declared by T is assigned.

A static field declared by T is used and the field is not a constant variable (§4.12.4).

T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.

A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface. BUT JLS DOES NOT STATE HERE THE SAME ABOUT STATIC METHODS THOUGH !

此外,12.4. Initialization of Classes and Interfaces says clearly :

Before a class is initialized, its direct superclass must be initialized

JLS 仅针对静态字段而非静态方法给出了此规则的排除!

初始化 Base 和 Derived 似乎是有意义的 - 如果 f() 在其主体内使用任何静态字段,则 Derived.f() 将使用 Derived 的静态字段(如果有),并且可以使用从 Base 继承的静态字段(如果 Derived 没有) - 这对初始化这两个类都是有意义的。

毕竟,简单的测试表明只有基类被初始化:

class Base {
static { System.out.println("Base init"); }

static void f() {}
}

class Derived extends Base {
static { System.out.println("Derived init"); }
}

public class Driver {
public static void main(String[] args) {
Derived.f(); // Only "Base init" printed...
}
}

最佳答案

也许令人困惑的是成员变量(包括静态成员变量)在 Java 中的工作方式。与方法不同,派生类中的成员变量不会继承其父类(super class)对应项;他们只是跟随他们。因此,如果您在 Base 中有一个变量 foo,在 Derived 中有一个变量 foo,那么如果您在 Base 中打印该变量,您将获得 Base 中的版本,如果您从 Derived 打印,您将获得 Derived 中的版本。

public class MyTest {

public static void main(String[] args) {

Base.f();
Derived.f();
}
}

class Base {
static void f() {
System.out.println("bar = " + bar);
}

protected static int bar = 1;
}

class Derived extends Base {
static void f() {
System.out.println("bar = " + bar);
}

private static int bar = 2;
}

给出:

bar = 1
bar = 2

因此,当您在 Base 中调用静态方法时,没有理由在 Derived 中运行初始化程序,因为 Base 永远无法直接访问 Derived 中的变量。

关于java - 当通过派生类引用调用基类的静态方法时,哪些类会被初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48607199/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com