(更新中)本博客是为了记录我(ZhongUncle)学习 Java 的时候记录的笔记,方便以后忘记的时候快速查看。由于 Java 与 C 语言家族的相似度非常高,所以这里只记录与 C/C++ 不同的地方,所以本博客并不适合编程初学者。
需要注意:在下文中,如果使用代码格式,类似java
这样,指的是命令或者目录/文件。而 Java 则指的是 Java 语言或者项目。
由于按照个人爱好和学习顺序编写,为了方便阅读,建议通过侧边目录跳转查看。
main函数的argv
参数不同
所有语言在编写 CLI 程序等时候,main
函数的参数必须要有一个参数来记录输入的命令。
语言 | 样式 |
---|---|
类 C 语言(C、C++、C#等) | int main(int argc, const char * argv[]) |
Java | public static void main(String[] args) |
输入命令的时候会将command <option> [arguments...]
按照空格放入那个字符串数组中(*argv[]
存放的是字符串首地址,可以直接理解成字符串)。详细内容还请移步《C语言中函数main的参数argc和argv是什么》。
但是二者有一个非常重要的区别。在类 C 语言中,*argv[0]
是command
字符串(也就是程序名);但是在 Java 中是不包含程序名的,也就是说,args[0]
就是第一个选项或者参数。
运行机制
下文中对于二者编译方法精简了许多,只是为了区别二者。如果你真的要研究编译过程或编译器,别看下面这段,请直接阅读《编译原理》或者其他人写的专门博客。
Java 与 C 语言程序的的运行机制差别巨大。
C 语言程序的运行方式是将 C 语言代码编译成机器代码(machine code),然后由计算机直接运行。而 Java 是将 Java 代码编译成字节码(bytecode),然后由 Java 运行时环境(JRE) 运行。
相比之下,Java 比较像脚本(说是像,是因为还是有个转换的过程,脚本是直接运行的),但是 Java 是可以像脚本一样运行的,可以看我的另外一篇博客:《如何使用Java写“脚本”(单个Java文件如何像脚本一样使用运行)》。
代码结构
Java 的代码结构是由类似 C++ 中的类(Class)构成。比如说最经典的“Hello World”,如果使用 Java 来写就是:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
可以看到 Java 源码就是由一个(或多个)类组成的,它们直接再互相联系。而这个包含了main
函数的类的名称HelloWorld
则是“程序”名称(为什么程序加引号请移步“转换和运行Java程序”这一节),该类又被称为“启动类”(还有另一种方法不使用main
方法启动,请移步“运行不含main
函数的类(不实用main方法的程序)”这一节)。
需要注意这里必须使用public static
修饰词来修饰main
函数,不然运行的时候会报错。
程序名称
上一节中说了,包含了main
函数的类的名称就是 Java 程序名称。但是需要注意,文件名也要统一为这个名称。如果源代码文件名和类名不一样,会报错误。这是因为 Java 的公共类需要在同名 Java 文件中。
下面以上面的代码举例,将源代码文件改名为test.java
,会报以下错误:
$ javac test.java
test.java:1: 错误: 类 HelloWorld 是公共的, 应在名为 HelloWorld.java 的文件中声明
public class HelloWorld {
^
1 个错误
转换和运行Java程序
Java 代码有三种使用方法:
- 第一种是类似脚本一样的方法,详细信息请移步:《如何使用Java写“脚本”(单个Java文件如何像脚本一样使用运行)》;
- 第二种是用
javac
将 Java 源码(.java
后缀文件)转换成 Java 字节码(存放在.class
后缀文件),然后使用java
运行; - 第三种是直接使用
java
“运行” Java 源码。
假设源码为:
//文件名“HelloWorld.java”
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
第二种方法
第二种方法编译及运行的命令如下:
$ javac HelloWorld.java
$ java HelloWorld
Hello World!
javac HelloWorld.java
会生成一个名为HelloWorld.class
的文件,内容为被编译的 Java 类数据(compiled Java class data)。
所以运行的时候其实并不是运行HelloWorld.class
文件,而是java
直接调用这个类运行。
这也是为什么包含了main
函数的类必须必须和源码文件的名称一样。因为不一样的话,编译的时候就也会出现对应错误的问题。
第三种方法
第三种方法编译及运行的命令如下:
$ java HelloWorld.java
Hello World!
可以看到效果是一样的。
运行不含main
函数的类(不实用main方法的程序)
上文一直在 Java 程序需要有一个main
函数,来给这个源码文件中的类们作为“入口”。那么一个 Java 程序可不可以没有main
函数的呢?
答案是可以的,只要使用静态块(Static Block),或者被称为静态初始化块(static initialization block)就可以。
静态块是一系列语句。当类被ClassLoader 载入到内存(stack memory)中的时候,这些语句只执行一次。
比如说下面这个程序就没有类:
class StaticBlock {
static
{
System.out.println("注意:这个类没有 main 函数");
System.exit(0);
}
}
运行效果如下:
$ java StaticBlock.java
注意:这个类没有 main 函数
可以看到能够正常运行的。
获取输入的字符串
Java 需要导入java.util.Scanner
才可以比较方便地获取输入数据,并不像 C 的getline
或者 C++ 的cin
是在标准库中的,而且使用起来也方便。
在导入java.util.Scanner
之后,还需要初始化一个扫描器:
Scanner scanner = new Scanner(System.in);
然后再用以下方式获取输入的字符串:
String aStr = scanner.nextLine();
拼接输出字符串
有时候需要输出类似总和为:123
这种样式的字符串,在 Java 中,不论是println
、print
,还是printf
,都不能使用\()
的方式插入,而是使用假号+
,如下:
System.out.print("总和为:" + sum);
System.out.printf("总和为:" + sum);
System.out.println("总和为:" + sum);
Java 如何在某个类中使用自身或父类创建对象
在类中声明成员变量的时候,如果成员变量是一个类的对象,那么需要在声明的时候就需要使用new Point()
。如下:
private Point xy = new Point();
之所以需要在声明的时候使用new Point()
,是因为创建对象的时候,需要事先规划留好适合的内存空间,但是 Java 并不会给每个成员变量都分配好空间,而是需要使用new Point()
来分配。
如果没有new Point()
来事先划分好空间,那么这个对象xy
新建出来是空的null
(编译的时候并不会报错)。
比如说这样的一段代码,没有使用new Point()
:
public class test {
public static void main(String[] argv) {
SpacePoint sp = new SpacePoint();
sp.set(1,2,3);
sp.print();
}
}
class Point {
private int x;
private int y;
public void set(int a, int b) {
x=a;
y=b;
}
public void print() {
System.out.print("x: " + x + ", y: " + y);
}
}
class SpacePoint extends Point {
private Point xy;
private int z;
public void set(int a, int b, int c) {
xy.set(a,b);
z=c;
}
public void print() {
xy.print();
System.out.println(", z: " + z);
}
}
可以看到下面编译时并不会报错,但是运行时会报错:
$ javac test.java
$ java test
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Point.print()" because "this.xy" is null
at SpacePoint.print(test.java:44)
at test.main(test.java:10)
希望能帮到有需要的人~