Java学习笔记(记录与C语言家族的不同)

(更新中)本博客是为了记录我(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 代码有三种使用方法:

  1. 第一种是类似脚本一样的方法,详细信息请移步:《如何使用Java写“脚本”(单个Java文件如何像脚本一样使用运行)》
  2. 第二种是用javac将 Java 源码(.java后缀文件)转换成 Java 字节码(存放在.class后缀文件),然后使用java运行;
  3. 第三种是直接使用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 中,不论是printlnprint,还是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)

希望能帮到有需要的人~

猜你喜欢

转载自blog.csdn.net/qq_33919450/article/details/129513167