一、系列文章导言

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

二、本期关注点

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

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

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

不过,请你大可放心,本文不是教你编译器编译这段程序机制,也不是教你字节码反编译后如何解读,更不会教你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方法的时候都会写上这么一段话。

 int main() {
...
return 0;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 public class HelloWorld {
public static void main(String[] args) {
main("Hello World");
} public static void main(String arg) {
System.out.println("Hello World");
}
}

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

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

 public class HelloWorld {
public static void main(String[] args) {
main("Hello World");
}
// 无递归出口,导致无穷递归
public static void main(String arg) {
main("Hello World");
}
}

七、结束语

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

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

不该被忽视的CoreJava细节(一)的更多相关文章

  1. 不该被忽视的CoreJava细节(四)

    令人纳闷的数组初始化细节 这个细节问题我很久以前就想深入研究一下,但是一直没有能够抽出时间,借这系列文章的东风,尽量解决掉这个"心头病". 下面以一维int数组为例,对数组初始化方 ...

  2. 不该被忽视的CoreJava细节(三)

    一.不该被遗忘的移位位运算 本文主要介绍移位运算(Shift Operation), 适当介绍一下其它相关的位运算. 甭说计算机刚发明那会,就连21世纪初那段日子,计算机内存都是KB/MB计算的.编写 ...

  3. ASP.NET常被忽视的一些细节

    原文:ASP.NET常被忽视的一些细节 前段时间碰到一个问题:为什么在ASP.NET程序中定时器有时候会不工作? 这个问题看起来很奇怪,代码好像也没错,但就是结果与预期不一致. 其实这里是ASP.NE ...

  4. C语言里面关于数组的一个容易忽视的小细节

    ginobili@VM_44_28_sles10sp1:~/code> cat test3.cpp #include <stdio.h> int main(){ char a[5] ...

  5. 【原创】构建高性能ASP.NET站点之三 细节决定成败

    原文:[原创]构建高性能ASP.NET站点之三 细节决定成败 构建高性能ASP.NET站点之三 细节决定成败 前言:曾经就因为一个小小的疏忽,从而导致了服务器崩溃了,后来才发现:原来就是因为一个循环而 ...

  6. 谈谈一些有趣的CSS题目(十二)-- 你该知道的字体 font-family

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  7. 谈谈一些有趣的CSS题目(十一)-- reset.css 知多少?

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  8. 谈谈一些有趣的CSS题目(三)-- 层叠顺序与堆栈上下文知多少

    开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...

  9. 谈谈一些有趣的CSS题目(一)-- 左边竖条的实现方法

    开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...

随机推荐

  1. Flask 入门(第一篇)

    1. 认识 Flask Flask 是一个微型 Web 框架,依赖于 jinjia2 模板系统和 Werkzeug WSGI(本质为 Socket 服务端) 服务,默认情况不支持数据库抽象层.表单验证 ...

  2. Neutron网络研究

    你将学到什么 虚拟机的Ping包是如何出外网的 DevStack环境准备 节点 硬件配置 网络配置 类型 操作系统 DevStack 4G 2CPU 50GB 2张网卡(NAT模式) VMWare虚拟 ...

  3. python测试模块-pytest介绍

    1.pytest介绍 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高. 它具有如下特点: •非常容易 ...

  4. java二分法查找实现代码

    package util; class BinarySearch { static int binarySearch(int[] array,int goal){//传入排好序的数组和目标数字 int ...

  5. 遍历json字符串 并 写入对应的文本框

    1.js代码: function getFlws(){ var url = urlpath + "bhjk/getJson2.sd?"; $.post(url,function(d ...

  6. Redis内核原理及读写一致企业级架构深入剖析1-综合组件环境实战

    1 Redis 工作模型 redis实际上是个单线程工作模型,其拥有较多的数据结构,并支持丰富的数据操作,redis目前是原生支持cluster模式.如果需要缓存能够支持更复杂的结构和操作,基于以上原 ...

  7. ng2学习--pipe使用

    We use our custom pipe the same way we use built-in pipes.(自定义Pipe和API里自带的Pipe使用方式一致) We must includ ...

  8. 在SpringBoot中使用Docker(利用dockerfile-maven-plugin插件)

    周末在家做了一个实验: 将Docker通过插件的方式集成到SpringBoot中 然后通过Maven命令根据项目中的Dockerfile自动生成Docker镜像,同时将镜像推送到远程Linux服务器( ...

  9. vue——解决“You may use special comments to disable some warnings. Use // eslint-disable-next-line to ignore the next line. Use /* eslint-disable */ to ignore all warnings in a file. ”

    在build/webpack.base.conf.js文件中,注释或者删除掉:module->rules中有关eslint的规则 module: { rules: [ //...(config. ...

  10. Windows下搭建QT环境

    必须软件 qt-windows-opensource-5.1.1-msvc2010-x86-offline qt-vs-addin-1.2.2-opensource支持vs2008.2010.2012 ...