• 不该被忽视的CoreJava细节(一)


    一、系列文章导言

    《不该被忽视的CoreJava细节》系列文章将会持续更新。我希望自己通过这一系列文章的写作,能与读者一起进步,逐步完善对Java体系结构的了解。

    二、本期关注点

    几乎翻看每一本与Java相关的入门书籍,教你跟着敲的第一个程序都会像下面这段代码一样。

    1 public class HelloWorld {
    2     public static void main(String[] args) {
    3         System.out.println("Hello World");
    4     }
    5 }

    这个程序貌似很简单,很多人都不以为意。但是,请大家扪心自问一下,你真的有花时间研究过吗或者说真的理解了吗?

    不过,请你大可放心,本文不是教你编译器编译这段程序机制,也不是教你字节码反编译后如何解读,更不会教你JVM如何处理这段程序以及类的装载机制。

    本期只是想让大家从最基础的角度读懂

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

    这段代码,仅此而已。

    三、main访问限定词趣闻

    根据Java语言规范,main方法必须声明为public。注意,Java语言是Sun公司对于Java语言的官方文档,在Java语言方面具有最高的权威性。

    但是,Java虚拟机规范并没有要求main方法一定是public

    两者的迥异导致,有些Java解释器能够执行非public修饰main方法所在的程序。

    不过,这个bug最终在JDK1.4中得到了修复,其后的所有main方法必须使用public作为访问修饰符。

    下面我尝试使用JDK1.7编写此方法,将main方法的public修改成private

    上图说明,至少在JDK1.7版本,这个bug已经被修复,无法使用非public修饰词修饰main方法。而且,我可以明确地告诉大家,1.7的虚拟机规范仍然没有指明必须这样做。

    四、static修饰词、void返回值对main意味什么

    先拿void开刀。如果在学过Java之前学过C语言,那么你一定会想起每次写main方法的时候都会写上这么一段话。

    1 int main() {
    2     ...
    3     return 0;
    4 }

    表示程序会给操作系统返回一个状态码0,操作系统收到状态码0表示程序正常退出。

    但是,我们的Java语言并没有返回值。也就是说,理论上Java程序并不会主动返回退出代码。

    那么到底Java程序有没有返回状态代码呢?事实上,如果Java程序正常退出,则会返回默认的退出码0。

    1 public class HelloWorld {
    2     public static void main(String[] args) {
    3         System.out.println("Hello World");
    4     }
    5 }   // 程序正常退出,退出码如下图。

    通过操作系统的errorlevel变量我们可以得到程序所返回的退出码。关于Java退出码需要再了解四点:

    1)Java程序的退出码并不会返回给JVM,这也就是方法用void的原因所在。

    2)Java程序的退出码返回给JVM所在的操作系统,正常退出默认返回给操作系统状态码值为0。

    3)退出码其实是约定俗成的。一般约定[0,99]内整数代表正常退出,[100-199]代表警告退出,大于等于200代表异常退出,但是不同的操作系统却不同。在Java中,默认的正常退出码为0,异常退出或警告码为1。

    1 public class HelloWorld {
    2     public static void main(String[] args) throws ClassNotFoundException{
    3         System.out.println("Hello World");
    4         Class.forName("");
    5     }
    6 }  // 不声明异常,声明异常,退出码均为 1

    4)可以自己设置退出状态码。Java调用java.lang.System.exit(int status)方法结束程序执行,并向操作系统返回status值。

    1 public class HelloWorld {
    2     public static void main(String[] args) {
    3         System.out.println("Hello World");
    4         System.exit(1000);
    5     }
    6 }  // 向JVM所在操作系统返回自定义状态码

    顺带提一句,如果在eclipse做实验并不会有状态码,或者说在eclipse跑程序,在命令行中状态码始终未0。其中差别始末,暂时未考虑清楚。

    五、参数列表--变态考题

     如果要出考题,前面的内容或许都用不到,基本没有什么可以出的题目。但是一提到main方法的参数列表,就有意思了。下面我就几个问题解答一下诸位可能存在的疑问。

    1)public static void main(String[] s) {}是否正确?

    咦,貌似和原来的有点区别,好像原来的形参是args。不明真相的群众可能一口咬定这句话是错误的,不巧的是,这句话确是没有任何无法问题的。

    1 public class HelloWorld {
    2     public static void main(String[] s) {
    3         System.out.println("Hello World");
    4     }
    5 }

    这段代码能够正确地输出结果。其中的原因在于:原来的args仅仅是参数,编译器是不会检查形参的变量名是否与args一致的,只要有一个合法的名字,编译器就认为没有问题,运行也不会出错。更进一步说,这个参数就是在控制台输入参数后用于获得参数用的,无非就是数组名字改了而已。

    如果编译程序的时候加上参数,比如javac HelloWorld.java 1 2 3

    1 public class HelloWorld {
    2     public static void main(String[] s) {
    3         System.out.println("Hello World");
    4         System.out.println(s[0]);  // 输出结果为1
    5     }
    6 }

    2)public static void main(String args)是否正确?

     这句代码编译器不能通过编译,缺少程序入口。

    3)public static void main(Char[] args)是否正确?

    这句代码编译器不能通过编译,缺少程序入口。

    上面三种类型说明,必须存在《code>public static void main(String[] 任意合法变量标识符) {}方法。这也是Java官方文档所规定的,必须遵守。 

    六、奇怪,怎么有2个main方法?

    为什么就不可能存在多个main方法?请看下面的例子。

    1 public class HelloWorld {
    2     public static void main(String[] args) {
    3         main("Hello World");
    4     }
    5     
    6     public static void main(String arg) {
    7         System.out.println("Hello World");
    8     }
    9 }

     本例是通过函数的重载实现的。其实很容易想到,在同一个类中有多个相同方法名存在很可能是使用了Java重载机制(编译器只检查方法名和参数列表,如果存在不同,则认为是两个不同的方法,编译器认为语法成立)。

    如果,一不小心写成下面这种样子,则会出现StackOverflowError异常,本质上是虚拟机方法栈帧存不下无穷递归过程的数据量。

    1 public class HelloWorld {
    2     public static void main(String[] args) {
    3         main("Hello World");
    4     }
    5     // 无递归出口,导致无穷递归
    6     public static void main(String arg) {
    7         main("Hello World");  
    8     }
    9 }

    七、结束语

    读完文本,是否觉得自己原来自己还有很多漏洞没有弥补。别慌,我想说的是:Java只是一种工具,一种为我们服务的编程工具。人与工具之间的关系不应该主次颠倒,应该尽量让工具为我们写出高质量应用而服务,而不是在这已经发展了20多年的工具面前如同乞讨者一般盲目仰慕前辈做出的巨大贡献。

    其实Java也就那样,掌握语言的核心知识,学点大牛写的API,那么随着时间的积累,代码量的增多,可能大家也可以作为第三方提供高质量的类库。鸡汤到此结束!

  • 相关阅读:
    关于Java集合框架,这篇讲的还算不错了,建议大家看看!
    其实SQL优化调优,就跟吃饭喝水一样简单,教你抓住SQL的本质!
    深度分析ReentrantLock源码及AQS源码,从入门到入坟,建议先收藏!
    建议收藏,从零开始创建一个Activiti工作流,手把手教你完成
    这个厉害了,ssm框架整合全过程,建议收藏起来好好看看
    阿里技术专家深入讲解,SpringMVC入门到进阶,看这一篇就够了
    python3.6:AttributeError: 'generator' object has no attribute 'next'
    【转】modulenotfounderror: no module named 'matplotlib._path'问题的解决
    sublime中使用插件anaconda而在代码中出现方框
    Linux上用sublime编辑Python时候出现"SyntaxError: Non-ASCII character ‘xe5′ in file"的问题
  • 原文地址:https://www.cnblogs.com/forget406/p/5705964.html
Copyright © 2020-2023  润新知