在我们进行编程的时候会经常遇到一个相同的问题,就是命名冲突。不同的人可能会定义同样的类和接口名,Java 中解决这个问题的主要方法就是「包」。
「包」类似计算机中的文件夹,正如我们在计算机管理文件,文件放在文件夹中一样,类和接口放在包中,文件夹一般是目录层次解决,Java 包也类似。
「包」有包名,这个名称以点号 .
分隔表示层次结构。比如,我们之前常用的 String
类就位于包 java.lang
下,其中 java
是上层包名,lang
是下层包名。带完整包名的类名称为其「完全限定名」,比如 String 类的完全限定名为 java.lang.String
。Java API 中所有的类和接口都位于包 java 或 javax 下,java 是标准包,javax 是扩展包。
声明类所在的包
定义类的时候,应该先使用关键字 package
声明其包名
package com.lgq.study.bean;
public class User {
}
以上声明类 User
的包名为 com.lgq.study.bean
包声明语句应该位于源代码的最前面,前面不能有注释外的其他语句。
包名和目录结构必须匹配,如果源文件的根目录为 D:\src\
,则上面的 User
类对应的文件 User.java
,其全路径就应该是 D:\src\com\lgq\study\bean\User.java
。如果不匹配, Java 会提示编译错误。
Java 中命名包名的一个惯例是使用域名作为前缀,因为域名是唯一的,一般按照域名的反序来定义包名,比如,域名是 apache.org
,包名就以 org.apache
开头。
类的导入
同一个包下的类之间互相引用是不需要包名的,可以直接使用。但如果类不在同一个包内,则必须要知道其所在的包。只有一个例外,
java.lang
包下的类可以直接使用,不需要引入,也不需要使用完全限定名,比如 String 类、System 类,其他包的类则不行。a
类的完全限定名导入类
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{1, 4, 2, 3};
java.util.Arrays.sort(arr);
System.out.println(java.util.Arrays.toString(arr));
}
}
上面使用 Arrays
类中的 sort
方法,通过完全限定名可以这样使用。
将用到的类引入当前类
引入的关键字是 import
,import
需要放在 package
定义之后,类定义之前:
package com.lgq.study;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{1, 4, 2, 3};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
import
操作还有如下写法:
-
import java.util.*
引入java.util
包下所有的直接类,而不会引入java.util
下嵌套包内的类。
静态导入
静态导入有一个 static
关键字,可以直接导入类的公开静态方法和成员。
package com.lgq.study;
import java.util.Arrays;
import static java.lang.System.out; //导入静态变量 out
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{1, 4, 2, 3};
Arrays.sort(arr);
out.println(Arrays.toString(arr)); //直接使用 out 变量
}
}
包的作用域
-
public
:标记为public
的部分可以被任意的类使用; -
private
:标记为private
的部分只能被定义它们的类使用; -
如果没有指定
public
或private
,这个部分(类、方法或变量)可以被同一个包中的所有类访问,而其他包内的类则不可以访问。 -
protected
:标记为protected
的部分不仅表明子类可以访问,还表明同一个包内的其他类可以访问,即使这些类不是子类也可以。
protected
和default
的区别就在于子类是否和父类在同级包中,protected
修饰的变量子类在其他包中也可以访问,但是default
情况下的变量子类只能在同级包中才可以访问。
可见性范围从小到大是:private
< 默认(包)< protected
< public
JAR 文件
在 Java 中,编译后的一个或多个包的 Java class
文件可以打包为一个文件,Java 中打包命令为 jar
,打包后的文件扩展名为 .jar
,一般称之为 jar
包,JAR 文件是压缩的,它使用了大家熟悉的 ZIP 压缩格式。
打包方式如下,首先到编译后的 java class
文件根目录,然后运行如下命令:
jar -cvf hello.jar com
com 是最上层包名
程序的编译与链接
「编译」是将源代码文件变成扩展名是 .class
的一种字节码,这个工作一般是由 javac
命令完成的。
「链接」是在运行时动态执行的,.class
文件不能直接运行,运行的是 Java
虚拟机,执行的就是 java
命令,这个命令解析 .class
文件,转换为机器能识别的二进制代码,然后运行。所谓「链接」就是根据引用到的类加载相应的字节码并执行。
Java 编译和运行时,都需要以参数指定一个 classpath
,即类路径。类路径可以有多个,对于直接的 class
文件,路径是 class
文件的根目录;对于 jar
包,路径是 jar
包的完整名称(包括路径和 jar 包名)。
在 Java 源代码编译时, Java 编译器会确定引用的每个类的完全限定名,确定的方式是根据 import
语句和 classpath
。如果导入的是完全限定名,则可以直接比较并确定。如果是模糊导入(import 带 .*
),则根据 classpath
找对应父包,再在父包下寻找是否有对应的类。如果多个模糊导入的包下都有同样的类名,则 Java 会提示编译错误,此时应该明确指定导入哪个类。
Java 运行时,会根据类的完全限定名寻找并加载类,寻找的方式就是在类路径中寻找,如果是 class
文件的根目录,则直接查看是否有对应的子目录及文件,如果是 jar
文件,则首先在内存中解压文件,然后再查看是否有对应的类。
参考资料
-
Java 编程的逻辑
-
Java 编程思想
-
Java 核心技术 卷 1
小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。如果在阅读过程中有疑问,请留言讨论.
作者:michaelliu