java入口函数解析

51 阅读5分钟

java入口函数解析

学习java接触到的第一个程序往往是helloworld。

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

那么入口函数public static void main(String[] args)是什么意思?它是怎么来的?

String[] args

不难看出,String[] args 是一个字符串数组,用于存储从命令行传递给程序的参数。这些参数在程序启动时被操作系统或者Java运行时环境(JRE)传递给 main 方法。

当你在命令行界面运行一个Java程序时,你通常会使用以下语法:

java YourProgram arg1 arg2 arg3

在这里,YourProgram 是你编译后的Java程序(实际上,它是一个包含 public static void main(String[] args) 方法的Java类),而 arg1arg2arg3 是你想传递给程序的命令行参数。

这些参数(arg1, arg2, arg3 等)会被放入 String[] args 数组中,然后传递给 main 方法。在 main 方法内,你可以通过索引访问这些参数,比如 args[0] 将会返回 "arg1"args[1] 将会返回 "arg2",依此类推。

这里注意和C语言区分开来

C语言中,argv[0]为程序名称,argv[1]及后才是参数

下面是一个简单的Java程序示例,演示如何接收和使用命令行参数:

public class CommandLineExample {
    public static void main(String[] args) {
        System.out.println("你传递了 " + args.length + " 个命令行参数。");

        for (int i = 0; i < args.length; i++) {
            System.out.println("参数 " + (i + 1) + ": " + args[i]);
        }
    }
}

如果你将这个程序保存为 CommandLineExample.java,然后通过命令行编译和运行它,你会看到以下效果:

编译:

javac CommandLineExample.java

运行:

java CommandLineExample Hello World 123

输出:

你传递了 3 个命令行参数。
参数 1: Hello
参数 2: World
参数 3: 123

如你所见,在这个例子中,String[] args 数组包含了三个元素:"Hello", "World", 和 "123",这些正是我们从命令行传递给程序的参数。这些参数可以在程序中用于各种目的,比如配置信息、输入文件名、网络地址等。

static

这意味着你不需要创建该类的对象实例就可以调用这个方法。这是有意义的,因为在程序开始运行时,你通常没有对象实例。

如果main()方法没有使用static修饰符,那么编译不会出错,但如果你试图执行该程序将会报错,提示main()方法不存在。因为包含main()的类并没有实例化(即没有这个类的对象)。

如果你很叛逆,非要运行这个程序呢?

办法是有的,既然main()的类并没有实例化,那么实例化这个主类就好了。以下是一个示例。

第一个程序:具有非静态 main 方法的 NonStaticMainExample
public class NonStaticMainExample {
    public void main(String[] args) {
        System.out.println("这是一个非静态的 main 方法。");
        for (int i = 0; i < args.length; i++) {
            System.out.println("参数 " + (i + 1) + ": " + args[i]);
        }
    }
}
第二个程序:创建 NonStaticMainExample 类的实例并调用其 main 方法
public class MainCaller {
    public static void main(String[] args) {
        // 创建 NonStaticMainExample 类的实例
        NonStaticMainExample exampleInstance = new NonStaticMainExample();

        // 调用该实例上的非静态 main 方法
        String[] newArgs = {"Hello", "World"};
        exampleInstance.main(newArgs);
    }
}

步骤:

  1. 将两个程序保存到单独的文件中,分别名为 NonStaticMainExample.javaMainCaller.java

  2. 使用 javac 编译这两个文件:

    javac NonStaticMainExample.java MainCaller.java
    
  3. 运行 MainCaller 程序:

    java MainCaller
    

当你运行 MainCaller,它将创建一个 NonStaticMainExample 类的实例,并调用该实例上的非静态 main 方法。这将输出:

这是一个非静态的 main 方法。
参数 1: Hello
参数 2: World

实际上,这没有什么意义,因为main已经失去了作为入口函数的功能,它只是该类的一个普通的方法。

public

声明主函数为public就是告诉其他的类可以访问这个函数。这意味着该方法可以从任何其他类或者任何在Java程序中的作用域内被访问。因为Java运行时环境(JRE)需要能够从外部访问这个方法来启动程序,所以它通常需要是 public

如果你把 public 改为 privateprotected,那么Java运行时环境将无法访问这个 main 方法,从而无法启动程序。具体来说:

  • public 改为 private:这样做会导致 main 方法只能在其定义的类内部被访问。Java运行时无法找到一个可访问的入口点,因此会抛出一个运行时错误。
  • public 改为 protected:这样做会使得 main 方法只能被同一个包内的其他类或该类的子类访问。与 private 相同,这也会导致Java运行时无法找到一个可访问的入口点。

在某些特殊情况下(例如,当 main 方法只用于单元测试或仅在一个更大的应用程序上下文中被调用时),你可能会看到非 publicmain 方法。然而,这样的 main 方法不能作为一个独立Java程序的入口点。

void

Java程序的标准入口点——main方法——必须返回void。这是Java语言规范的一部分,如果你尝试改变返回类型并作为程序的入口点使用,那么Java运行时环境(JRE)将无法找到有效的入口点。

同static一样,你可以将void改成任何其他类型。它依然能过编译,但没法作为入口函数运行;能在其他类中被调用,但没什么意义。