枚举和类中的主方法是否有不同之处?

3
在以下代码中:
enum Rank {
    FIRST(20), SECOND(0), THIRD(8);
    Rank(int value) {
        System.out.print(value);
    } 

    public static void main (String[] args) {
        System.out.println(" " + Rank.values().length);
    }
}

这会产生以下输出:
2008 3

如果 main 方法在其他类中声明,例如:
class XYZ {
    public static void main (String[] args) {
        System.out.println("\n" + Rank.values().length);
    }
}

输出结果只有3。 枚举中的main和类中的main有什么区别?为什么我有两个不同的输出?

1
枚举和其他类之间没有区别。只是一个差异在于当类被加载时,代码会在那里运行。有点类似于如果在XYZ中添加了一个静态块并在其中加入了打印语句。 - Stultuske
1
你确定你的第一段代码片段的大括号是否正确? - thomas.mc.work
我无法重现你的问题。当我使用外部类时,我得到了输出 2008 3。我还在 Rank 类中注释掉了 main 方法,但输出仍然相同。 - Blip
枚举实例是“public static final”的。如果您向“XYZ”添加等效字段和ctor,则会执行相同操作,因为静态字段在类首次使用时由类加载器初始化。 - Kevin
4个回答

4

枚举常量是静态的。它们在类初始化时进行初始化(enum只是一个类)。这意味着当您调用引用enum类型的类的main方法时,所有值都使用构造函数创建。

如果其他类没有以任何方式引用enum,则不会打印任何输出,因为没有评估enum


无法重现您的问题。当我使用外部类时,我得到了输出2008 3。我还在“Rank”中注释掉了主方法,但输出仍然相同。 - Blip

2
类和枚举之间最显著的区别在于枚举具有预定义的实例。当枚举加载时,它的值被打印出来,执行Enum的构造函数以创建级别,然后打印其值。普通类的main方法没有方法实现,也不会自动创建对象。你必须创建类的实例。希望你明白我的意思。
更多详情请参见Enum 因此,在main方法中没有差异,但是对于你而言,枚举的实例是在虚拟机加载枚举时创建的,因此差异是可见的。 :)
根据@Blip的要求,我正在更新我的答案。因此,即使将main方法分离,也不会改变任何事情。因为主方法仍然引用Rank枚举,因此运行时加载了Enum,正如我们已经知道Enums的实例将在加载类的同时创建,因此它仍将执行构造函数,因此您将看到输出为2008 3。

无法重现您的问题。当我使用外部类时,输出为“2008 3”。我还在Rank中注释掉了主方法,但输出仍然相同。 - Blip
@Blip 这并不是关于主方法的分离,而是关于枚举实例创建的时机。枚举和类之间最显着的区别在于其实例的创建方式。当 JVM 加载特定的枚举时,它会负责枚举的实例创建。因此,即使您将主方法分离,仍将输出 2008 3,但请尝试从 System.out.println 语句中移除 Rank。此外,请参考我提供的链接,了解有关枚举的一些基本差异 :) :) 希望对您有所帮助。 - Bilbo Baggins
我已经核对了,发现是正确的。感谢指出这一点。我请求您更改您的答案,以纠正在问题中提到的差异点。 - Blip

2

您实际上看到的是枚举的构造函数打印。

因此,在开始时,创建了Rank.FIRST并使用20调用了System.out.print(value);

然后,Rank.SECONDRank.THIRD也是同样的情况;这都是由类加载器完成的,因为EnumCreation正在使用Rank枚举。

由于Rank中的构造函数使用的是print而不是println,所以它们都显示在一行上。

然后,当EnumCreation进入主方法时,它会打印一个空格,后跟Rank.values().length和一个换行符。

XYZ进入主方法时,它应该做同样的事情;但它会打印一个换行符而不是空格。

从类的角度来看,您有三个类。 Rank,EnumCreation和XYZ。 Rank和EnumCreation碰巧共享1个*.java文件。

希望这能帮助澄清问题!


看起来问题中两个类的主方法都被编辑以删除 System.out.println() 语句。由于这个改变,当 EnumCreation 运行时,它仍然会导致 2008 打印,因为类加载器在运行时会加载同一文件中的 Rank,从而导致所有三个枚举值被静态构造。而且,由于 XYZ 现在完全没有引用 Rank 类或其主方法中的任何指令,所以它将不会执行任何操作。 - anonymous
无法重现你的问题。当我使用外部类时,得到了输出2008 3。我还注释了Rank中的主方法,但输出仍然相同。 - Blip

0

类初始化程序和实例(或对象)初始化程序之间有所区别。当加载类时运行类初始化程序,这通常发生在第一次引用它时。对象初始化程序是构造函数,仅在使用new关键字创建新实例时运行(除反射外)。

枚举是静态实例。您可以将它们视为单例 - 您永远不会使用new实例化枚举

所以假设我有这个定义

public class Foo {
    static{
        System.out.println("Someone loaded the class");
    }

    public Foo(){
        System.out.print("Foo constructor");
    }

    public static void main(String[] args) {
        System.out.println("Making Foo");
        Foo foo = new Foo();

    }
}

输出结果为:

有人加载了这个类
制造 Foo
Foo 构造函数

Enum 将像 Foo 中的静态块一样工作。

这是一个 Enum 示例:

public enum FooValues {
    HELLO,GOODBYE,WHAT;

    private FooValues(){
        System.out.println(this);
    }

    public static void main(String[] args) {
        System.out.println("in main");
    }
}

这会给出

你好
再见
什么
在主函数中

因为当Enum被加载时,所有值都在类加载阶段初始化,然后运行main方法。


无法重现您的问题。当我使用外部类时,获得的输出为 2008 3。我还将 Rank 中的主方法注释掉,但输出仍然相同。 - Blip
@Blip,我相信你的评论是针对楼主的,是吗?你可能想从我的回答中删除它,并将其放在楼主的问题上。 - MadConan
不,它也是针对您的,以便您可以纠正这种情况的答案。我已经在该问题的所有帖子上发表了此评论,因为个人可以采取适当的行动。 - Blip

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