从Java主函数入口psvm谈起
C/C++当中,入口函数只要名为main()
即可被识别并执行,虽然规范要求main函数返回值为int类型,但错误地将main返回值声明为void类型不影响C/C++程序的运行。而在JAVA程序编写的时候,若不将主类的入口main
函数声明为public static void main(String[] argv)
的形式,就无法运行,这一串关键词的首字母缩写即psvm。接下来就对这些4个关键字进行逐一分析。
在《Java语言规范》中,对于Java虚拟机的启动给出了明确的定义:Java虚拟机是通过加载指定的类,然后调用该类中的main方法而启动的。也就是说,通过调用某个指定类的main方法,传递给他单个的字符串数组参数,就可以启动Java虚拟机。一个main方法想要被执行,需要经过几个步骤,首先对应的类需要被虚拟机加载,然后需要进行链接和初始化、之后才是调用main方法。那么一个方法想要被调用,根据他的访问限定符以及方法类型不同,被调用的条件也是不同的。
why public?
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
default
(即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。private
: 在同一类内可见。使用对象:变量、方法。注意:不能修饰类(外部类)public
: 对所有类可见。使用对象:类、接口、变量、方法protected
: 对同一包内的类和所有子类可见。使用对象:变量、方法。注意:不能修饰类(外部类)。
以上四种控制符都可以用来修饰方法,但是被修饰的方法的访问权限就不同了。
而对于main
方法来说,我们需要通过JVM直接调用他,那么就需要他的限定符必须是public
的,否则是无法访问的。
why static?
static
是静态修饰符,被他修饰的方法我们称之为静态方法,静态方法有一个特点,那就是静态方法独立于该类的任何对象,它不依赖类特定的实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。
而对于main
方法来说,他的调用过程是经历了类加载、链接和初始化的。但是并没有被实例化过,这时候如果想要调用一个类中的方法。那么这个方法必须是静态方法,否则是无法调用的。
why void?
在C/C++中,规范上要求main
的返回值为int
类型,这个返回值在是程序退出时的 exit code,一般被命令解释器或其他外部程序调用已确定流程是否完成。一般正常情况下用 0 返回,非 0 为异常退出。
而在Java中,这个退出过程是由JVM进行控制的,在发生以下两种情况时,程序会终止其所有行为并退出:
- 所有不是后台守护线程的线程全部终止。
- 某个线程调用了Runtime类或者System类的exit方法,并且安全管理器并不禁止exit操作。
上面的两种情况中,第二种情况一旦发生,JVM是不会管main方法有没有执行完的,他都会终止所有行为并退出,这时候main方法的返回值是没有任何意义的。所以,main方法的返回值就被固定要求为void。
why String[] ?
Java应用程序是可以通过命令行接受参数传入的,从命令行传递的参数可以在java程序中接收,并且可以用作输入。因为命令行参数最终都是以字符串的形式传递的,并且有的时候命令行参数不止一个,所以就可能传递多个参数。这时候,作为Java应用程序执行的入口,main方法就需要能够接受这多个字符串参数,那么就使用字符串数组了。
总结
main方法是JVM执行的入口,为了方便JVM调用,所以需要将他的访问权限设置为public。
静态方法可以方便JVM直接调用,无需实例化对象。
因为JVM的退出其实是不完全依赖main方法的,所以JVM并不会接收main方法的返回值,所以给main方法定义一个返回值没有任何意义。所以main方法的返回值为void。
为了方便main函数可以接受多个字符串参数作为入参,所以他的形参类型被定义为String[]。