为什么Java主方法是静态的?

Java # eyz0方法的方法签名是:

public static void main(String[] args) {
...
}

为什么这个方法必须是静态的?

518136 次浏览

这只是一种惯例,但可能比另一种更方便。使用静态主程序,调用Java程序所需要知道的只是类的名称和位置。如果它不是静态的,您还必须知道如何实例化该类,或者要求该类具有空构造函数。

c++、c#和Java中的main方法是静态的。

这是因为它们可以被运行时引擎没有调用,必须实例化任何对象,然后main主体中的代码将完成其余的工作。

在main方法被调用之前,没有对象被实例化。使用static关键字意味着可以在不创建任何对象的情况下调用方法。

否则,它将需要一个对象的实例来执行。但是它必须从头开始调用,而不是首先构造对象,因为它通常是main()函数(bootstrap)的任务,解析参数并构造对象,通常是通过使用这些参数/程序参数。

如果不是,如果有多个构造函数,应该使用哪个构造函数?

Java语言规范中有更多关于Java程序初始化和执行的信息。

各种类型的applet、midlet、servlet和bean被构造,然后在它们上调用生命周期方法。调用main是对主类所做的全部工作,因此不需要在被多次调用的对象中保存状态。将main固定在另一个类上是很正常的(尽管这不是一个好主意),这将妨碍使用类创建main对象。

这只是一种惯例。JVM当然可以处理非静态的主方法,如果这是惯例的话。毕竟,您可以在类上定义静态初始化器,并在到达main()方法之前实例化无数对象。

该方法是静态的,否则就会产生歧义:应该调用哪个构造函数?特别是如果你的类是这样的:

public class JavaClass{
protected JavaClass(int x){}
public void main(String[] args){
}
}

JVM是否应该调用new JavaClass(int)?x应该通过什么?

如果不是,JVM是否应该实例化JavaClass而不运行任何构造函数方法?我认为不应该这样,因为那样会使你的整个类出现特殊情况——有时你有一个没有初始化的实例,你必须在每个可能被调用的方法中检查它。

在调用入口点之前,JVM必须实例化一个类,这有太多的边缘情况和模糊性,因此没有意义。这就是为什么main是静态的。

我不知道为什么main总是标记为public

如果主方法不是静态的,则需要从程序外部创建主类的对象。你想怎么做呢?

这只是惯例。事实上,甚至main()的名称和传入的参数都是纯粹的约定。

当您运行Java .exe(或Windows上的javaw.exe)时,真正发生的是几个Java本机接口(JNI)调用。这些调用加载的DLL是真正的JVM(没错,java.exe不是JVM)。JNI是我们用来连接虚拟机世界和C、c++等语言世界的工具。反过来也是对的——不使用JNI是不可能让JVM运行的(至少据我所知)。

基本上,java.exe是一个超级简单的C应用程序,它解析命令行,在JVM中创建一个新的String数组来保存这些参数,解析出您指定的包含main()的类名,使用JNI调用查找main()方法本身,然后调用main()方法,将新创建的字符串数组作为参数传入。这非常非常类似于您从Java中使用反射时所做的事情——它只是使用了令人混淆的命名本机函数调用。

编写自己版本的java.exe(源代码随JDK一起分发)并让它做一些完全不同的事情是完全合法的。事实上,这正是我们对所有基于java的应用程序所做的。

我们的每个Java应用程序都有自己的启动器。我们这样做主要是为了得到我们自己的图标和进程名,但在其他情况下,当我们想做一些常规的main()调用之外的事情来让事情继续进行时,它也很方便(例如,在一种情况下,我们正在进行COM互操作性,我们实际上将COM句柄传递给main()而不是字符串数组)。

总之,它是静态的原因是b/c,这很方便。它被称为“main”的原因是它必须是某种东西,main()是他们在旧的C语言中所做的(在那些日子里,函数的名字很重要)。我认为java.exe可以允许你只指定一个完全限定的主方法名,而不仅仅是类(java com.mycompany.Foo.someSpecialMain)——但这只会让ide更难自动检测项目中的“可启动”类。

因为静态成员不是任何特定类的一部分,而且主方法不需要创建它的Object,但仍然可以引用所有其他类。

Static表示该方法是类方法。并且调用时不需要任何类的对象。

由于程序从main()和开始执行,java是纯面向对象的程序,其中对象在main()中声明,这意味着main()在对象创建之前被调用,因此如果main()是非静态的,那么就需要一个对象,因为静态意味着不需要对象..........

静态方法不需要任何对象。它直接运行,所以main直接运行。

public关键字是一个访问修饰符,允许程序员进行控制 类成员的可见性。当类成员前面有public时,则 成员可以被声明它的类之外的代码访问

public相反的是private,它防止成员被定义在类之外的代码使用。

在这种情况下,main()必须声明为public,因为它必须被调用

.

.

. 关键字static允许 调用main(),而不必实例化类的特定实例。这是必要的,因为Java解释器在创建任何对象之前调用main()

关键字void只是告诉编译器main()没有返回值。

这是一个经常被问到的问题,为什么main()在Java中是静态的。

回答:我们知道在Java中,JVM从main()开始执行。当JVM执行main()时,包含main()的类不会被实例化,因此我们不能在没有引用它的对象的情况下调用非静态方法。因此,为了调用它,我们将其设置为静态的,因此类装入器将所有静态方法装入JVM上下文内存空间中,JVM可以从那里直接调用它们。

在主方法中使用静态关键字是因为在主方法中没有发生任何实例化。 但是对象是构造的而不是调用的,因此我们在main方法中使用静态关键字。 在jvm上下文中,当类加载到内存中时创建内存。所有静态成员都存在于内存中。如果我们现在把主方法设置为静态的,它就会在内存中,并且可以被JVM (class.main(..))访问,这样我们就可以调用主方法,甚至不需要创建堆

我认为关键字“静态”使主方法成为类方法,类方法只有它的一个副本,可以被所有人共享,而且,它不需要一个对象来引用。因此,当编译驱动程序类时,可以调用主方法。(我只是在java的字母级别,如果我错了,对不起)

Main()是静态的,因为;在应用程序生命周期的这一点上,应用程序堆栈本质上是过程化的,因为还没有实例化对象。

这是一个干净的石板。您的应用程序此时正在运行,即使没有声明任何对象(请记住,有过程性和OO编码模式)。作为开发人员,通过创建对象的实例并依赖于在其中编译的代码,将应用程序转换为面向对象的解决方案。

面向对象的优点有几百万个显而易见的理由。然而,大多数VB开发人员在代码中经常使用“goto”这样的关键字的日子已经一去不复返了。“goto”是VB中的一个过程命令,它被OO对应的方法调用所取代。

您还可以将静态入口点(main)视为纯粹的自由。如果Java足够不同,可以实例化一个对象,并在运行时只向你呈现该实例,那么你就别无选择,只能编写一个过程化应用程序。对于Java来说,这听起来可能难以想象,但可能有许多场景都需要过程化方法。

这可能是一个非常晦涩的回答。记住,“类”只是一个相互关联的代码的集合。“实例”是这个类的一个孤立的、活生生的、自主的代。

任何应用程序的真正入口点都是静态方法。如果Java语言支持实例方法作为“入口点”,那么运行时将需要在内部将其作为静态方法实现,该方法构造对象的实例,然后调用实例方法。

有了这些,我将研究选择以下三个选项中的一个的基本原理:

  1. 就像我们今天看到的static void main()
  2. 在新构造的对象上调用的实例方法void main()
  3. 使用类型的构造函数作为入口点(例如,如果入口类被称为Program,那么执行将有效地由new Program()组成)。

分解:

# EYZ0

  1. 调用外围类的静态构造函数。
  2. 调用静态方法main()

# EYZ0

  1. 调用外围类的静态构造函数。
  2. 通过有效地调用new ClassName()构造外围类的实例。
  3. 调用实例方法main()

# EYZ0

  1. 调用外围类的静态构造函数。
  2. 构造类的实例(然后不做任何操作,只是返回)。

理由是:

这个我倒着讲。

请记住,Java的设计目标之一是强调(尽可能要求)良好的面向对象编程实践。在这种情况下,对象的构造函数初始化是对象,但不应该对对象的行为负责。因此,给出new ClassName()入口点的规范会使新Java开发人员感到困惑,因为它强制每个应用程序上的“理想”构造函数设计出现异常。

通过将main()设置为实例方法,可以解决上述问题。但是,它要求规范列出入口类的构造函数的签名以及main()方法的签名,从而增加了复杂性。

总之,指定static void main()将创建复杂度最低的规范,同时遵循将行为置于方法中的原则. #。考虑到实现main()方法本身构造类的实例并调用实例方法是多么简单,将main()指定为实例方法并没有真正的优势。

这只是一个惯例,我们可以在这里看到:

方法必须声明为公共的和静态的,它不能返回任何值 值,并且它必须接受String数组作为参数。默认情况下, 第一个非选项参数是要调用的类的名称。 应该使用完全限定的类名。如果-jar选项为 指定后,第一个非选项参数是JAR存档的名称 类包含应用程序的类和资源文件 由Main-Class manifest头指示的启动类

http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/java.html#description

public静态void关键字意味着Java虚拟机(JVM)解释器可以调用程序的主方法来启动程序(public),而无需创建类的实例(static),并且程序结束时不会将数据返回给Java VM解释器(void)。

< p >来源: # EYZ0 < / p >

为什么公共静态无效主(字符串[]args) ?

这就是Java语言和Java虚拟机是如何设计和编写的。

Oracle Java Language Specification

看看第十二章执行——12.1.4调用Test.main:

最后,在完成Test类的初始化之后(在此期间可能发生了其他相应的加载、链接和初始化),调用Test的main方法。

方法main必须声明为public、static和void。它必须接受一个字符串数组的参数。此方法可以声明为任意一种

public static void main(String[] args)

public static void main(String... args)

Oracle Java虚拟机规格

看看第2章Java编程语言概念-第2.17节执行:

Java虚拟机通过调用某个指定类的main方法并向其传递一个参数(字符串数组)来开始执行。这将导致指定的类被加载(§2.17.2),链接(§2.17.3)到它使用的其他类型,并初始化(§2.17.4)。方法main必须声明为public、static和void。

Oracle OpenJDK Source

下载并提取源jar,看看JVM是如何编写的,查看../launcher/java.c,其中包含命令java [-options] class [args...]背后的原生C代码:

/*
* Get the application's main class.
* ... ...
*/
if (jarfile != 0) {
mainClassName = GetMainClassName(env, jarfile);


... ...


mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */


... ...


/* Get the application's main method */
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");


... ...


{    /* Make sure the main method is public */
jint mods;
jmethodID mid;
jobject obj = (*env)->ToReflectedMethod(env, mainClass,
mainID, JNI_TRUE);


... ...


/* Build argument array */
mainArgs = NewPlatformStringArray(env, argv, argc);
if (mainArgs == NULL) {
ReportExceptionDescription(env);
goto leave;
}


/* Invoke main method. */
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);


... ...

来自java.sun.com(网站上有更多信息):

主要方法是静态的,以使Java VM解释器能够在不首先创建控件类实例的情况下启动类。控件类的实例在程序启动后在main方法中创建。

我的理解一直很简单,就像任何静态方法一样,可以在不创建相关类的实例的情况下调用主方法,允许它在程序中的任何其他方法之前运行。如果它不是静态的,你就必须在调用它之前实例化一个对象——这就产生了一个“先有鸡还是先有蛋”的问题,因为main方法通常是你在程序开始时用来实例化对象的。

原型public static void main(String[])是在JLS中定义的约定:

方法main必须声明为public、static和void。它必须指定一个形式形参(§8.4.1),其声明类型为String数组。

在JVM规范5.2. 虚拟机启动中,我们可以读到:

Java虚拟机通过创建一个初始类来启动,这个初始类是使用bootstrap类装入器(§5.3.1)以依赖于实现的方式指定的。然后,Java虚拟机链接初始类,初始化它,并调用public类方法void main(String[])。此方法的调用将驱动所有进一步的执行。组成主方法的Java虚拟机指令的执行可能导致链接(并因此创建)其他类和接口,以及调用其他方法。

有趣的是,在JVM规范中并没有提到主方法必须是静态的。 但是规范还规定Java虚拟机在

之前执行两个步骤

类或接口的初始化包括执行类或接口的初始化方法。

2.9. 特殊的方法:

定义一个类或接口初始化方法:

一个类或接口最多有一个类或接口初始化方法,并通过调用该方法进行初始化(§5.5)。类或接口的初始化方法有一个特殊的名称<clinit>,不带参数,并且是空的。

类或接口初始化方法实例初始化方法不同,定义如下:

在Java虚拟机级别,每个用Java编程语言(JLS§8.8)编写的构造函数都以实例初始化方法的形式出现,其特殊名称为<init>

所以JVM初始化了一个类或接口初始化方法而不是实例初始化方法,它实际上是一个构造函数。 所以他们不需要在JVM规范中提到主方法必须是静态的,因为在调用主方法之前不创建实例这一事实暗示了这一点

让我们简单地假设,不需要static作为应用程序入口点。

一个应用程序类看起来是这样的:

class MyApplication {
public MyApplication(){
// Some init code here
}
public void main(String[] args){
// real application code here
}
}

构造函数代码和main方法之间的区别是必要的,因为在OO中,构造函数只应确保实例正确地为初始化。初始化后,实例可以用于预期的“服务”。将完整的应用程序代码放到构造函数中会破坏这一点。

因此,这种方法将在应用程序上强制三个不同的契约:

  • 必须是一个默认构造函数。否则,JVM将不知道调用哪个构造函数以及应该提供哪些参数。
  • 必须main方法1。好吧,这并不奇怪。
  • 不得abstract。否则,JVM无法实例化它。

另一方面,static方法只需要一个合约:

  • 必须有一个main方法1

在这里,abstract和多个构造函数都不重要。

由于Java被设计为一种简单的语言对于用户来说,因此应用程序入口点被设计为使用一个契约的简单方式,而不是使用三个独立的脆弱契约的复杂方式,这并不奇怪。

请注意:这个参数是,表示JVM或JRE内部的简单性。这个参数是关于用户的简单性。

人力资源> < p > < 在这里,完整的签名只算作一份合同。

最近,类似的问题也出现在了程序员网站上。SE

博士TL;部分公认的答案是,

在Java中,使用public static void main(String[] args)的原因是

  1. # EYZ0希望
  2. 由精通C语言(而不是Java)的人编写的代码
  3. 由习惯在新闻上运行附言的人执行

http://i.stack.imgur.com/qcmzP.png

< p >, < br > 对于c#,可以这么说,理由是轨迹上相似。语言设计人员保持来自Java的程序员熟悉的程序入口点语法。安德斯·海尔斯伯格说

...我们使用c#的方法只是提供一个替代方案…对Java程序员来说……

...

public static void main(String args[])是什么意思?

  1. public是一个访问说明符,意味着任何人都可以访问/调用它,例如JVM(Java虚拟机)。
  2. static允许在创建类的对象之前调用main()。这是必要的,因为JVM在创建任何对象之前调用main()。因为它是静态的,所以可以通过类直接调用。

    class demo {
    private int length;
    private static int breadth;
    void output(){
    length=5;
    System.out.println(length);
    }
    
    
    static void staticOutput(){
    breadth=10;
    System.out.println(breadth);
    }
    
    
    public static  void main(String args[]){
    demo d1=new demo();
    d1.output(); // Note here output() function is not static so here
    // we need to create object
    staticOutput(); // Note here staticOutput() function is  static so here
    // we needn't to create object Similar is the case with main
    /* Although:
    demo.staticOutput();  Works fine
    d1.staticOutput();  Works fine */
    }
    }
    

    类似地,有时我们对用户定义的方法使用静态,这样我们就不需要创建对象

  3. void表示正在声明main()方法

  4. String[] args指定main()方法中的唯一参数。

    args -一个包含类类型为String的对象数组的参数

任何在Java中声明为静态的方法都属于类本身。 同样,特定类的静态方法只能通过引用类来访问,如Class_name.method_name();

因此,在访问静态方法之前不需要实例化类。

因此main()方法被声明为static,这样就可以在不创建该类对象的情况下访问它。

因为我们用存在主方法的类名保存程序(或者从程序开始执行的地方,适用于没有main()方法()的类(高级级别))。所以通过上面提到的方法:

Class_name.method_name();

可以访问主方法。

简而言之,当程序被编译时,它会搜索具有String参数的main()方法,例如:由于在开始时它没有实例化该类的作用域,因此main()方法被声明为静态的。

让我用更简单的方式来解释这些事情:

public static void main(String args[])

除了applet,所有Java应用程序都从main()开始执行。

关键字public是一个访问修饰符,允许从类外部调用成员。

使用static是因为它允许调用main(),而不必实例化该类的特定实例。

void表示main()不返回任何值。

我不知道JVM是否在对象实例化之前调用main方法…但是main()方法是静态的还有一个更有力的原因…当JVM调用类的主方法(比如Person)时。它通过“Person.main ()”调用它。您可以看到,JVM通过类名调用它。这就是为什么main()方法应该是静态和公共的,以便JVM可以访问它。

希望有帮助。如果是的话,请在评论中告诉我。

基本上,我们将这些数据成员和成员函数设置为STATIC,它们不执行任何与对象相关的任务。对于main方法,我们将其设置为STATIC,因为它与object无关,因为无论我们是否创建对象,main方法总是运行。

这背后的原因很简单,因为对象不需要调用静态方法,如果它是非静态方法,java虚拟机先创建对象,然后调用main()方法,这将导致额外的内存分配问题。

程序的主要方法保留字 静态,这意味着它被允许在静态上下文中使用。上下文与程序运行期间计算机内存的使用有关。当虚拟机加载一个程序时,它为它创建静态上下文,分配计算机内存来存储程序及其数据,等等。EYZ4是稍后在程序运行期间进行的某种内存分配。如果不允许主方法在静态上下文中运行,则程序将无法启动。

static -当JVM调用主方法时,被调用的类不存在对象,因此它必须有静态方法来允许从类调用。

当您使用java命令执行Java虚拟机(JVM)时,

java ClassName argument1 argument2 ...

当您执行您的应用程序时,您指定它的类名作为java命令的参数,如上所述

JVM尝试调用您指定的类的主方法

-在这一点上,类的对象还没有被创建。

声明main为静态allows JVM到invokewithout创建

. class的instance

让我们回到命令

ClassName是JVM的command-line argument,它告诉JVM要执行哪个类。在ClassName之后,还可以指定list of Strings(用空格分隔)作为JVM将传递给应用程序的命令行参数。-这样的参数可以用来指定运行应用程序的选项(例如文件名)-这就是为什么在主文件中有一个名为String[] args的参数

引用:# EYZ0

主方法总是需要是静态的,因为在运行时JVM不会创建任何对象来调用主方法,正如我们所知,在java中静态方法是唯一可以使用类名调用的方法,所以主方法总是需要是静态的。

更多信息请访问这个视频:https://www.youtube.com/watch?v=Z7rPNwg-bfk&feature=youtu.be