main 方法在枚举和类中的工作方式是不是不同?

Posted

技术标签:

【中文标题】main 方法在枚举和类中的工作方式是不是不同?【英文标题】:Does main method work differently in enums and classes?main 方法在枚举和类中的工作方式是否不同? 【发布时间】:2015-08-12 06:16:01 【问题描述】:

在以下代码中:

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 有什么区别?为什么我有两个不同的输出?

【问题讨论】:

枚举和其他类没有区别。只是在加载类时运行代码这一事实有所不同。有点像你在 XYZ 中有一个静态块并在那里添加了一个打印语句。 你确定你的第一个代码 sn-p 对左花括号和右花括号是正确的吗? 我无法重现您的问题。当我使用外部类时,我得到了输出2008 3。我还在Rank 中注释掉了他的main 方法,但输出仍然相同 枚举实例为public static final。如果您向XYZ 添加等效字段和一个ctor,它会做同样的事情,因为静态字段在类第一次使用时由类加载器初始化。 【参考方案1】:

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

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

【讨论】:

无法重现您的问题。当我使用外部类时,我得到了输出2008 3。我还在Rank 中注释掉了他的主要方法,但输出仍然相同【参考方案2】:

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

所以一开始Rank.FIRST 被创建,System.out.print(value); 被调用为 20。

那么Rank.SECONDRank.THIRD 也会发生同样的事情;这都是由类加载器完成的,因为EnumCreation 正在使用Rank 枚举。

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

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

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

不过,从班级的角度来看,您有 3 个班级。排名、EnumCreation 和 XYZ。 Rank 和 EnumCreation 恰好共享 1 个 *.java 文件。

希望这有助于解决问题!

【讨论】:

看起来问题中两个类中的主要方法都被编辑以删除System.out.println() 语句。由于该更改,EnumCreation 在运行时仍会导致 2008 打印,因为类加载器会在运行时将Rank 加载到同一文件中,从而导致所有 3 个枚举值都是静态构造的。而且由于XYZ 现在根本没有对Rank 类的引用或其主方法中的任何指令,它不会做任何事情。 无法重现您的问题。当我使用外部类时,我得到了输出2008 3。我还在Rank 中注释掉了他的主要方法,但输出仍然相同【参考方案3】:

类和枚举之间最显着的区别是 ENUM 预定义了它的实例。该值在枚举加载时被打印,它执行 Enum 的构造函数以创建排名,然后依次打印其值。为普通类执行 main 时没有方法实现,也没有自动创建对象。你必须创建类的实例。希望你明白我的意思。

关于Enum的更多详情

因此 main 方法没有区别,但您可以看到区别,因为枚举的实例是在 VM 加载枚举时创建的。 :)

根据@Blip 的要求,我正在更新我的答案,因此即使您分离出主要方法,它也不会改变任何事情。由于 main 方法仍然引用 Rank 枚举,因此 Enum 正在由运行时加载,并且我们已经知道 Enums 的实例将在加载类时创建,它仍将执行构造函数,因此您将看到输出为 2008 3

【讨论】:

无法重现您的问题。当我使用外部类时,我得到了输出2008 3。我还在Rank 中注释掉了他的主要方法,但输出仍然相同 @Blip 这不是关于分离主要方法,而是关于何时创建 Enum 的实例。看到这是枚举和类之间最显着的区别。 JVM 在加载该特定枚举时会负责为枚举创建实例。因此,即使您分离出该主要方法,您仍然会得到 2008 3 作为输出,但请尝试从 System.out.println 语句中删除 Rank。进一步参考我为枚举提供的链接将给出一些关于差异的基本概念:) :) 希望它有所帮助 我检查并发现它是正确的。感谢您指出。我会要求您更改答案,以纠正问题中提到的这一差异点。【参考方案4】:

Class 初始化程序和实例(或Object)初始化程序之间存在差异。 Class 初始化程序在 Class 加载时运行,这通常在第一次被引用时发生。 Object 初始化器是构造函数,仅在使用 new 关键字创建新实例时运行(禁止反射)。

Enums 是静态实例。你可以把它们想象成单例——你从来没有newEnum

假设我有这个Class 定义

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 很确定您的评论是针对 OP 的,是吗?可能想从我的答案中删除它并将其放在 OP 的问题上。 不,它也针对您,以便您可以更正此场景的答案此外,我已对这个问题的所有帖子发表了此评论,因为个人可以采取适当的行动。

以上是关于main 方法在枚举和类中的工作方式是不是不同?的主要内容,如果未能解决你的问题,请参考以下文章

为啥c#中的main方法总是放在类中而不是c++中

课程作业02

枚举类中的 c++ 运算符重载

Blazor DI 在 .razor 和商务类中的工作方式不同。为啥?

为啥在函数和类中处理未绑定的局部变量有区别?

类中的 Python 主函数