通过 Enum 初始化 Interface 的静态变量

Initialize static variables of Interface via Enum

我试图理解下面的行为,我只是想通过枚举方法初始化接口的静态变量。

enum Hello {
    ProfileResolver();

    public Hello resolve() {
        System.out.println("resolve method called!!!!");
        return ProfileResolver;
    }
}
public interface Resolver{
  Hello hello = Hello.ProfileResolver.resolve(); // this should called when creating an instace of any implementation
}

实施class如下

public class Impl implements Resolver{
}

现在如果

public static void main(String[] arg){
   Resolver resolver = new Impl();
}

此时我期待 Impl 对象的对象初始化之前,接口的 hello 变量必须初始化并解析调用的方法,但事实并非如此。 当我将 Resolver 声明为 class 而不是接口时,它按预期工作。 谁能帮我理解一下?

这里是Java中类型静态初始化的指定触发器。这是来自 Java Language Specification

12.4.1. When Initialization Occurs
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.
  • 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).

When a class is initialized, its superclasses are initialized (if they have not been previously initialized), as well as any superinterfaces (§8.1.5) that declare any default methods (§9.4.3) (if they have not been previously initialized). Initialization of an interface does not, of itself, cause initialization of any of its superinterfaces.

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.

Invocation of certain reflective methods in class Class and in package java.lang.reflect also causes class or interface initialization.

A class or interface will not be initialized under any other circumstance.

仔细分析,您的代码不满足Resolver接口静态初始化的任何要求...

  • new Impl()会导致Impl的初始化,但这不会导致Resolver的初始化,因为Resolver没有任何默认值方法(请参阅我的粗斜体文本强调)。

  • 不需要对 Resolver 类型的引用触发初始化

  • 使这段代码触发Resolver初始化的方法是向它添加一个默认方法(这里没有意义),或者读取它的静态变量:

    public static void main(String[] args) throws Exception {
        Resolver resolver = new Impl();
        System.out.println(Resolver.hello); //causes initialization
    }
    

如果您使用 Hello hello = Hello.ProfileResolver.resolve(); 通过 resolve() 方法触发一些预期的副作用,那么 please don't.