为什么我们可以在内部类中拥有静态final成员,但无法拥有静态方法?

7

为什么我们可以在非静态内部类中拥有静态final成员,但无法拥有静态方法?

我们能否在不实例化内部类的情况下访问内部类的静态final成员变量?

1个回答

7

在一个 静态 的 "内部" 类中,您可以拥有静态方法。

public class Outer {
    static String world() {
        return "world!";
    }
    static class Inner {
        static String helloWorld() {
            return "Hello " + Outer.world();
        }
    }   
    public static void main(String args[]) {
        System.out.println(Outer.Inner.helloWorld());
        // prints "Hello world!"
    }
}

准确地说,根据JLS术语(8.1.3),Inner被称为嵌套类:

尽管内部类可能不声明静态成员,但它们可以继承非编译时常量的静态成员。未作为内部类的嵌套类可以按照Java编程语言的通常规则自由声明静态成员。


此外,内部类并非完全可以拥有静态常量成员,更确切地说,它们还必须是编译时常量。以下示例说明了区别:
public class InnerStaticFinal {
    class InnerWithConstant {
        static final int n = 0;
        // OKAY! Compile-time constant!
    }
    class InnerWithNotConstant {
        static final Integer n = 0;
        // DOESN'T COMPILE! Not a constant!
    }
}

这种情况下允许编译时常量很明显:它们在编译时被内联。

编译时内联是一项实现细节。更重要的是,在代码可以合法地使用任何一个的情况下,用常量加载的最终静态字段的行为与用相同常量加载的静态实例字段的行为是无法区分的。非静态内部类的静态成员的适当行为可能会产生歧义,但对于用常量加载的静态 final 字段,解决歧义的两种可能方式都会产生相同的结果。 - supercat
1
@supercat “编译时内联”不是实现细节,它是规范所规定的:“对常量变量(§4.12.4)的引用必须在编译时解析为常量变量初始化程序指定的值V”。与此同时,非常量static变量的问题已经得到修复。从JDK16开始,您可以在内部类中使用static变量和方法。 - Holger
1
@VinaySharma 因为规范如此规定。只有原始值和字符串可以作为编译时常量。 - Holger
1
@supercat,您不必这样做,因为在内部类中放置static字段没有技术问题。但是,JLS中内部类的确切形式确实令人惊讶地模糊不清。由于内部和外部类总是一起生成的,因此可能存在实现特定的细节,如果两个类由不同的编译器生成,则无法正常工作(事实上,过去曾经有这样的差异,现在仍然可能存在)。 - Holger
1
@supercat 这是不同的事情。在您之前的评论中,您发布了一个没有 final 的示例。但是当字段满足编译时常量的形式标准时,其格式是强制性的。有两个影响。首先,JVM本身将在运行任何类初始化器代码之前初始化该字段。其次,在针对该类编译新代码并且存在对该字段的访问时,编译器必须从类文件中读取常量值并使用它。规范规定这种(源代码)访问不会导致类初始化(无运行时访问)。 - Holger
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接