最近重回Java了,先梳理一下Java的文件组织和一些编译上的连接逻辑。 这篇博客适合刚接触Java,能编写简单的Java程序,或者像我一样忘了Java文件的组织逻辑的菜鸟。这里没有语法知识,那些到处有,我更多的是讲一下逻辑和思想
Java中文件组织层次为:项目(project)>包(package)>源文件(file)>类(class)。这里自底向上梳理一下
类是Java程序的基本组成。Java中的类在结构上又有公共类,主类、内部类之说。这里旨在说明类的结构思想,不谈及类的定义。
Java与C++都是面向对象编程语言,都有类的概念。但是,如果你跟我一样是从先学了C++再接触Java,那你初见Java版HelloWorld时一定跟我一样一脸懵逼。
public class HelloWorld{ public static void main(String args[]){ System.out.println("Hello,world!"); } }为什么一上来就定义一个类? main函数为什么写在类里面? 这个Java的程序结构有关。
Java程序都是且只能由类组成。
这句话可以理解为:Java所有变量,函数都要写到类定义里去。Java程序入口就是类,整个过程就是类之间的协作。 什么?全局变量?全局函数?通通写到类里去,静态(static)变量,静态函数不会吗! 所以,从C++过来刚接触Java的同学,你需要一种不同于C++的思想
万物皆可为类
可以这样理解,不同于C++,Java诞生的时候面向对象编程思想相对成熟了。除了具有实际意义的物品能定义成对象,甚至行为、属性等也可以给它一个负责执行和管理的抽象类。 这样,HelloWorld可以这样理解:首先我们定义了一个HelloWorld类,这个类负责执行main函数。 随着你对Java的深入接触,你会渐渐觉得这种思想很受用。
先给出定义:
公共(public)类与非公共类:在类定义前有public关键字的类为公共类,没有的为非公共类。 主类:含有主函数(main)的类称为主类。主类是程序的入口
大部分情况下,一个程序只有一个入口类,而且这个类往往是公有的。 【注意】:
主类不一定是公有类。一个Java程序允许有多个主类,也就是存在多个main函数,但一个类中只能有一个main函数。 这可能很奇怪,不过Java程序执行的时候是需要指定入口类的,所以并不会冲突。 可以看这个例子: /** HellowWorld.java **/ public class HelloWorld{ public static void main(String args[]){ System.out.println("Hello,world!"); } } class NotHelloWorld{ public static void main(String args[]){ System.out.println("This is 'Hello,world!'"); } }【疑问】从上面的例子中发现一个问题,既然非公有类是包内可访问的,那为什么还有public函数(main)?包外可以使用这个函数吗? 【回答】这貌似确实冲突了。首先,包外无法访问这个类的,当然无法使用这个函数。但是,我们不得不保留这种表达,因为这个非公有类(或匿名类)可能实现了某个公共接口。
Java中源文件与Java类是具有对应关系的。它们之中最重要的联系就是:
源文件主名(不包括后缀.java)必须与公共类名一致。
【注意】一个源文件内可以定义多个类,但只能有一个公有类。 往细了说,就是:一个源文件至多可以有一个公共类和任意个非公共类。如果有公有类,必须和文件名一致,否则会报错;如果没有,文件名可以任意。 在开发中,一个Java源文件往往包含一个同名公共类,所以我们常常用该公共类指代该文件。
Java编译生成的文件为.class文件,文件名一般与类名相同。
.class文件与类是一一对应的。
不论该类是否公有,甚至对于匿名内部类,都会生成与之对应的.class文件。如果在一个文件中定义了多个类,编译会得到多个.class文件。
包是Java中文件的组织结构。类似于文件系统中文件夹机制对文件管理的作用,而且包路径实际上也是对应源文件的存放路径。
Java通过package语句实现包机制。package语句指定了该文件中所有类的路径。
pakage语句必须在文件最顶部(不含注释),否则编译报错。 pakage语句中的包路径必须与源文件的存放路径(相对于项目根路径)一致,否则在引用时会报错。
【疑】既然文件已经放到相应的位置了,为什么还需要pakage语句显示声明? 【答】 尽管放到正确的包路径中,没有pakage声明的文件中的类在编译过程中会被放到默认包(未命名)中,无法被引用。 所以,你必须保证,源文件的存放路径与package语句中的包路径都正确且一致。
在一个类中引用另一个类可以使用包名+类名或者通过import语句引入后直接使用类名。
import语句位于package语句与类定义之间。
【注意】 引用同一包内的类不用import语句,否则会报错,编译器会自动查找包类定义的类。但是如果没有package语句声明,即使同一个路径下的两个类也无法相互引用。也就是说没有package语句的类是找不到的,记住一句话:
没有package(语句),就不能被import。
我们知道C/C++通过#include包含文件实现文件的链接。那Java呢?
先提一下,Java可以使用通配符一次编译多个文件。 如javac A*.java可以一次性编译以A开头的所有文件。 但是,一般情况下,我们只想编译一个主类以及它依赖的所有类。这种时候只需编译这个主类就可以了。
Java在编译一个类时,会自动查找并编译(如果需要的话)其引用的类文件。
----答案是-classpath。很熟悉?就是JDK安装时候配置的系统变量
----上面说过的两个文件,.java文件和.class文件。
(多数情况下)如果只找到.java文件,编译之。如果只找到.class文件,使用之。如果找到二者,检查时间截,若发现.java文件修改过,重新编译生成最新的.class文件。 所以,如果类A引用了类B,且二者都编译过存在对应的.class文件,然后同时修改二者之后,你只需要编译类A,编译器会自动更新类B。