【问题标题】:Why does Java Specifications want the main method of a program to be void only? [duplicate]为什么 Java 规范只希望程序的 main 方法是无效的? [复制]
【发布时间】:2015-06-30 05:28:41
【问题描述】:

虽然返回类型不是方法签名的一部分,但 JVM 会寻找确切的声明为

 public static void main(String[] args)

我的假设是,由于方法签名没有包含“返回类型”,所以我必须是 允许更改返回类型。

但如果我将其更改为public static int main(String[] args) 并返回一个值让我们说 0,JVM 无法执行程序并退出并出现错误

Error: Main method must return a value of type void in class TestData, please 
define the main method as:
   public static void main(String[] args)

为什么 Java 规范只希望 main 方法为 void? 当返回类型不是方法签名的一部分时,为什么会有这个限制?

这个问题与Why is main() in java void? 不同:这个问题已关闭,因为它是基于意见的,而我正在寻找 JVM 调用此方法的代码位置/进程,以及迫使他们这样做的限制是什么保持此方法无效。他们做出了哪些设计决策(以及背后的原因),记录在哪里。

我正在寻找事实,以便知道这样做的原因。 请不要在未仔细阅读问题详细信息的情况下将其标记为重复。

PS:退出,是另外一回事。我更关心程序的进入。另外,返回的值可能不是给JVM使用的,限制为void,限制了可扩展性。

到目前为止,我从这个问题中学到的是:Java 规范已明确固定返回类型,以避免对可能期望此值返回到 OS 的迁移程序员 (C/CPP) 造成混淆,但由于 JVM 介于两者之间值永远不会返回给操作系统。为了这个特殊目的(向操作系统返回值),他们提供了 System.exit() 方法。


对于那些建议返回类型是签名的一部分的人——尝试在一个类中定义以下两个方法

    public static void main(String[] a){

    }
    public static String main(String[] a){

    }

你会得到一个编译错误,因为这两个方法的签名是一样的。

【问题讨论】:

  • JVM 这样做是因为规范是这么说的,但我假设你想知道为什么规范这么说。
  • 我的问题还没有回答!!为什么!!!没有人在谈论“为什么”是不允许的。每个人都将其标记为重复或回答这是“应该如何”。我的问题是“为什么”。在您回答我的确切问题之前,请删除此重复标记。
  • @CodeFighter 您似乎遇到的问题是,您不能接受“这就是它的设计方式”的答案,创作者决定将主要入口点设为@987654326 @。这可能有很多原因,您需要一台时间机器和一个读心器来获得答案。
  • @CodeFighter main 有任何返回值几乎没有意义,因为当main 无论如何存在时JVM 可能不会退出,保证在调用System.exit 或唯一运行时退出Threads 是守护线程,那么,返回一个可以忽略或更改的值有什​​么意义?
  • @CodeFighter 这是真的,但一般来说,它就是为此而设计的。 JVM 在方法签名上放置了一个 required ,它形成了我们有义务遵守的合同。这就像说为什么你不能改变接口方法的返回类型,语言规范禁止它。

标签: java jvm return-type


【解决方案1】:

main is void 在JLS 12.1.4 Invoke Test.main 中指定:

方法main 必须声明为publicstaticvoid

有时为什么?的答案是因为规范这么说(又名 Quod Ego Dixit,或因为我这么说 (Terry Pratchett))。有时语言设计者的决定是不可用的,我们唯一能做的就是猜测。这也是明显的重复 (Why is main() in java void?) 主要基于意见而被关闭的原因。

现在 - 对我来说 - 显而易见的原因:JLS 12.8 Program Exit 说:

当以下两种情况之一发生时,程序会终止其所有活动并退出:

  • 所有非守护线程的线程都会终止。
  • 某线程调用RuntimeSystem类的exit方法,退出操作未被安全管理器禁止。

这意味着main方法的结束并不一定意味着程序的结束。 main 方法的返回码在 C 等语言中具有众所周知的含义:它是进程退出码。当main 方法可能在进程本身结束之前很久就退出时,此含义不适用。

大多数非平凡的 Java 应用程序都有 - 通常 - 一个短暂的 main 方法,它启动一个或多个长期存在的非守护线程。允许来自 Java main 方法的返回代码可能意味着实际上并不存在的含义:返回值是进程退出代码。所以明确指定 main 必须有一个 void 返回类型是一件好事:它减少了混淆或分配不存在的含义。

【讨论】:

    【解决方案2】:

    main 方法毕竟可能不是退出点。由于多线程,当主线程返回时,可能会出现另一个线程在球场上保持程序活着。在这种情况下,退出代码没有意义。

    【讨论】:

      【解决方案3】:

      为什么无效?

      如果您希望将某些状态返回给操作系统,您可以使用任何现有方法。最常见的是System.exit(int status)

      如果您的主线程在其他线程之前完成,则返回值无关紧要。 这与当时不支持多线程的 c/c++ 形成对比。

      就像一个摇摆应用程序在完成 main 之后仍然可以在 EDT 上运行。

      如果你还在考虑“入口”点:但返回类型总是谈论出口。

      所以它只是无效的,因为我们有状态信号器返回一个值,或者在其他情况下不返回。 尽管如此,没有其他意义,因为它是这样设计的。另一个想法不同的开发人员可能会提出另一个想法来解决相同的情况。取决于。

      【讨论】:

        【解决方案4】:

        如中所述 http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.8

        12.8。程序退出

        当发生以下两种情况之一时,程序会终止其所有活动并退出 发生:

        所有不是守护线程的线程都终止。

        某个线程调用了Runtime类或System类的exit方法, 并且退出操作未被安全管理器禁止。

        如果所有正在运行的线程都是守护进程,则程序退出。因此,如果您有一个非守护线程,则 main 方法可能会在程序结束之前返回。

        程序的生命周期可以延长 main 方法的生命周期,返回值可能会在程序的后面决定。

        我认为这就是他们使用 System.exit() 作为返回点的原因。

        【讨论】:

          【解决方案5】:

          您不能从 Java Docs 中查看下面的内容,因为您的主要方法作为退出点,您需要使方法无效。或者您可以选择在 main 结束时显式调用 system.exit()。

          终止当前运行的 Java 虚拟机。该参数用作状态码;按照惯例,非零状态码表示异常终止。

          【讨论】:

          • 我的问题是“为什么”当方法返回某些东西时它不能作为退出点。唯一的影响是返回的值没有在任何地方使用。
          【解决方案6】:

          据我所知,

          main 方法以void 作为返回类型的原因是,一旦main 方法执行完毕,并不意味着整个程序就完成了。它可能在幕后启动并运行了一些线程。即使主线程死了,仍然有可能运行子线程。在这种情况下,main 的返回类型没有多大意义。

          JVM 将监视程序完成状态以释放内存,不必向JVM 返回表明程序已完成的内容。在 C 语言中,我们直接与 OS 通信。因此,可以选择将 int 值返回给 OS。表示执行已完成并开始释放内存。但在 java 中,JVM 将与操作系统通信。但不是程序,所以我们不需要从 main 返回任何东西。

          希望这能消除您的疑虑。

          【讨论】:

            【解决方案7】:

            如果您要求 JVM 运行一个类,java 运行时将在您的类中查找该签名 public static void main(String[] args) 那是你与 JVM 的合约,如果没有,它就不会执行。 如果您想要返回 int 代码,请使用 System.exit

            【讨论】:

            • 我同意,但我的问题是JVM为什么担心返回类型?
            • @MohitKanwar 因为在JVM中,返回类型是part of the method descriptor
            • @Turing85 不错。这为我打开了一些进一步探索的窗口。谢谢。
            【解决方案8】:

            控制台程序返回一个 int 返回码,因此在传统的 C 程序中,int main(int argc, char** argv) 似乎是合乎逻辑的。

            在 Java 中,exception 作为一种新的控制流机制被引入,并且多线程 被模拟或现在实现。 System.exit(int returnCode) 可以在任何地方退出。

            这意味着对 main 的调用嵌入在一段代码中,并且最简洁(极简,更少的情况,return 0 没有魔力)是返回 0 的默认,除了System.exit.

            请注意,java 旨在强烈“改进”C,尤其是 C++。就像使用完整的 Unicode 而不是字节的字符串和字符。

            【讨论】:

              【解决方案9】:

              Java 被设计为Platform independent language。因此,如果它的main() 方法返回一个值(如 0 或 1 或任何值),它可以被不同的平台以不同的方式解释或理解。因此,与 CCpp 不同的是,main() 方法不能返回值。

              【讨论】:

              • 但是,Java 不会直接返回操作系统,我想 JVM 介于两者之间。因此,在使用 exit() 之前,返回的值不会进入操作系统。
              【解决方案10】:

              主要原因是在常见用例中,尤其是在多线程和 GUI 应用程序中,您不希望在 main.xml 中有返回值。但是如果你真的有这样的用例,你可以使用 exit 方法。这就是您正在寻找的原因。

              【讨论】:

                【解决方案11】:

                Java 中的 main 方法是什么?

                Java 中的 Main 方法是任何核心 Java 程序的入口点。请记住,我们不是在谈论 Servlet、MIDlet 或任何其他提供生命周期方法来控制执行的容器管理的 Java 程序。在核心 Java 程序中,当您键入 java main-class-name 时,从 main 方法开始执行,JVM 搜索该类中的 public static void main(String args[]) 方法如果它没有找到抛出错误 NoSuchMethodError:main 并终止的方法。

                Java 中 main 方法的签名

                Main 方法必须严格遵循其语法;否则 JVM 将无法找到它,您的程序将无法运行。这是 main 方法的确切签名:

                public static void main(String args[])

                这个签名是经典的签名,从 Java 开始就存在,但是在 Java5 中引入了可变参数或 varargs,您还可以使用 varargs 语法在 Java 中声明 main 方法,如下例所示:

                public static void main(String...args)

                记住 varargs 版本的 java main 方法只能在 Java 1.5 或更高版本中工作。除了 public、static 和 void,还有一些关键字,如 final、synchronized 和 strictfp,在 java main 方法的签名中是允许的。

                为什么Java中的main方法是静态的

                为什么 main 方法在 Java 中是 public static void 现在进入重点“为什么 main 方法在 Java 中是静态的”,周围有很多原因,但这里有几个对我来说有意义的原因:

                1. 由于 main 方法是静态的,Java 虚拟机可以在不创建任何包含 main 方法的类实例的情况下调用它。

                2. 由于 C 和 C++ 也有类似的 main 方法作为程序执行的入口点,因此遵循该约定只会对 Java 有所帮助。

                3. 1234563
                4. 在 Java 中的类中声明的任何内容都属于引用类型,并且需要在使用它们之前创建对象,但是静态方法和静态数据被加载到 JVM 内称为上下文的单独内存中,该内存在加载类时创建.如果 main 方法是静态的,那么它将在 JVM 上下文中加载并可供执行。

                为什么 main 方法在 Java 中是公开的

                Java 指定了几个访问修饰符,例如私有的、受保护的和公共的。在 Java 中声明为 public 的任何方法或变量都可以从该类的外部访问。由于 main 方法在 Java,JVM可以很方便的访问和执行。

                为什么Java中的main方法是无效的

                由于 Java 中的 main 方法不应该返回任何值,因此将其设为 void,这仅意味着 main 没有返回任何内容。

                总结:

                1. Java 中的 Main 方法必须声明为 public、static 和 void,否则 JVM 将无法运行 Java 程序。

                2. 如果在提供给 Java 命令的类中找不到预定义签名的 main 方法,JVM 会抛出 NoSuchMethodException:main。例如。如果你运行 java Helloworld,JVM 会在 HelloWorld.class 文件中搜索 public static void main String args[]) 方法。

                3. Main 方法是任何 Core Java 程序的入口点。从 main 方法开始执行。

                4. Main 方法由 Java 中称为“main”线程的特殊线程运行。您的 Java 程序将一直运行,直到您的主线程正在运行或从 main 方法产生的任何非守护线程正在运行。

                1. 当您看到“线程主线程中的异常”时,例如 Thread main 中的异常:Java.lang.NullPointerException 这意味着在主线程中抛出了异常。

                2. 您可以从 Java 1.5 开始使用可变参数语法声明 main 方法,例如 public static void main(String...args)

                3. 除了 static、void 和 public,您还可以在 Java 中的 main 方法的签名中使用 final、synchronized 和 strictfp 修饰符。

                1. Java 中的 Main 方法可以像 Java 中的任何其他方法一样被重载,但 JVM 只会调用具有指定签名的 main 方法 以上。
                1. 您可以在 main 方法的签名中使用 throws 子句,并且可以抛出任何已检查或未检查的异常。

                2. 甚至在 JVM 调用 main 方法之前执行静态初始化程序块。它们在类被 JVM 加载到内存时执行。

                我希望这已经回答了你关于主要方法的问题:)

                更新响应:

                您的答案有一个小问题:返回类型不是 方法签名.. 因此,JVM 不能抛出异常 "NoSuchMethodException:main" 如果返回类型不同。

                如果返回类型不同并且返回类型是方法签名的一部分,则它不会返回“NoSuchMethodException:main”。看看这个截图:

                【讨论】:

                • 您的回答有一个小问题:返回类型不是方法签名的一部分。因此,如果返回类型不同,JVM 不得抛出异常“NoSuchMethodException:main”。
                • 用支持图片更新了我的评论:)
                • 没有帮助。 :) 问题是为什么要抛出这个异常?
                • 这只是因为这个类是公开的。
                【解决方案12】:

                我们可以说,main 方法作为类初始化方法,因为它满足类初始化标准之一;请参考http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.412.4.1部分--

                T是一个类,调用了T声明的静态方法。

                现在,根据 JVM 规范,return 指令用于从声明为 void 的方法、实例初始化方法、以及类或接口初始化方法返回。 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.11.8

                退货说明请看这里:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.10.1.9.return

                【讨论】:

                • main 不是类初始化方法。
                猜你喜欢
                • 2010-10-07
                • 2016-05-30
                • 2011-07-10
                • 1970-01-01
                • 2018-05-09
                • 1970-01-01
                • 2014-06-22
                • 1970-01-01
                • 2013-04-11
                相关资源
                最近更新 更多