为了更好地组织类,Java提供了包机制。包是类的容器,用于分隔类名空间。如果没有指定包名,所有的示例都属于一个默认的无名包。在包的基础上再引入权限的概念,它包含类的访问权限和类成员的访问权限。
1、使用package定义编译的时候存放的位置
/* 包的关键字“package” */
/* 这个 Pack 类会存放在 a/b/c/d 这个四级目录的d目录下 */
package a.b.c.d;
public class Package {
public static void main(String args[]){
System.out.println("Hello,World");
}
}
编译运行的命令如下:
代码非常简单就是打印字符串,但是使用 package 这个关键字后我们可以指定这个类放入哪个文件夹(即包)里面。有什么用呢,如果一个工程下面有多个同名类,那么可以使用 import 来导入具体调用哪个包下面的类,如下代码实现:
先写两个类,它们处于不同的包名下面:
2、下图大致写出了引入包的作用,假如有两个人写了同样的一个类Math类,里面实现了不同的运算方法,我们可以通过目录来区分开来。
代码主体的架构,lisi只实现了加法运算,zhangsan实现了加法的运算并且在运行结果上+2,且张三实现了减法运行。Package类通过import调用lisi和zhangsan不同的包。
lisi的Math.java代码如下
/* 处于d1这个包 */
package a.b.c.d1;
public class Math{
public static int add(int x,int y){
return x + y;
}
}
zhangsan的Math.java代码如下:
/* 处于d2这个包 */
package a.b.c.d2;
public class Math{
public static int add(int x,int y){
return x + y + 2;
}
public static int sub(int x,int y){
return x - y;
}
}
Package.java代码如下
下面是对这些包的调用,使用 import 关键字来导入后便可使用它们包下的类
import a.b.c.d1.*;
import a.b.c.d2.*;
public class Package {
public static void main(String args[]){
System.out.println(a.b.c.d1.Math.add(1,2));
System.out.println(a.b.c.d2.Math.add(1,2));
System.out.println(a.b.c.d2.Math.sub(1,2));
}
}
编译运行结果如下:
3、在上述的代码基础上在张三目录添加Print.java类,用于打印信息,在Package.java类中,可以通过包名来使用类的方法,如果该方法没有同名的类方法,可以不使用包名直接使用该方法.
Print.java
/* 也处于d2这个包 */
package a.b.c.d2;
public class Print{
public static void printInfo(){
System.out.println("package a.b.c.d2;");
}
}
Package.java
/* import 表示导入,下面导入这个(d1、d2)目录下的所有类 */
import a.b.c.d1.*;
import a.b.c.d2.*;
public class Package {
public static void main(String args[]){
/* add */
System.out.println(a.b.c.d1.Math.add(1,2));
System.out.println(a.b.c.d2.Math.add(1,2));
/* sub */
System.out.println(a.b.c.d2.Math.sub(1,2));
a.b.c.d2.Print.printInfo();
/* 如果没有同名的类,也可以直接使用下面的调用方式 */
Print.printInfo();
}
}
编译运行结果
在将这个程序进行编译后,在各个包下就会生成对应的类,但是有个问题,假如将这个程序交给客户,我们不仅要给 Pack.java 给客户,还得把整个包目录也交给客户,这样就会比较麻烦,你给个程序,还需要给这么多目录文件,有没有办法呢,当然是有的,我们可以将包进行打包,我在 java 虚拟机下使用 jar 命令可以对包进行打包(具体使用 jar -help 看帮助说明),使用
jar -cf my.jar a
这个命令对 a 这个包进行压缩,命名为 my.jar,之后便可删除 a 目录,在执行程序时,只需要将这个包添加到环境变量里面即可,具体使用 CLASSPATH(编译的时候用来查找代码,运行的时候来查找文件和压缩包),当然在此之前我们也可以使用命令先查看下这个类去哪里查找这些源代码的,使用如下命令:
javac Pack.java -verbose
在进行打包编译后,我们使用如下命令把压缩包添加进环境变量
export CLASSPATH=.:my.jar
表明在当前目录(.)和(my.jar)这个目录下查找,再次编译即可成功,这样以后给客户只需要提供类和这个压缩包就可以了。
4、张三、李四开发的代码,在编译之后都生成在a目录下面,我们可以把a目录打包成jar包之后,给用户,这样也可以不用开源自己的代码。使用jar把a目录压缩成jar包,并且在环境变量中添加my.jar包,主程序Package就可以使用,张三和李四实现的方法了。
添加环境变量暂时保留
5、访问权限
在了解了包的概念后,就可以很好的讲解权限的问题了,java 下的权限分两种,一个是类权限,一个是类成员权限,类权限有 public class 和 class ,类成员权限有 private、default、protected、public 这四种,下面以程序来分别讲解上述的几种权限。
首先定义一个类,它处于 b 包下,这个类的权限为 “public”
public class可以被外包访问,class只能在本包中访问
Mymath.java
package b;
/* public 表示这个类本程序内和本包内都可以访问,外包也能访问 */
/* 如果没有定义 public , 本程序内和本包内都可以访问,但外包不能访问*/
//class Mymath{ 编译失败
public class Mymath{
}
Pack.java
package a;
public class Pack{
public static void main(String args[]){
Mymath m = new Mymath();
}
}
编译java包失败,需要把Mymath定义成public才可以编译通
重新编译
6、将5的代码Mymath类也定义在包a中,那样Mymath没有加public也可以在pack类中访问
Mymath.java
package a;
class Mymath{
//public class Mymath{
}
Pack.java
package a;
//import b.*;
public class Pack{
public static void main(String args[]){
Mymath m = new Mymath();
}
}
编译结果:
7、同一个包中,一个类的属性定义为private,无法被另外一个类访问。去掉private为默认属性,可以被另外一个类访问。
Mymath.java
package a;
class Mymath{
private int x;
//int x; 去掉private则可以编译通过
}
Pack.java
package a;
//import b.*;
public class Pack{
public static void main(String args[]){
Mymath m = new Mymath();
/* 下面这步操作肯定出错,因为x 是 Mymath 的私有成员,
只能在同一个类里面去访问 */
m.x = 0;
}
}
编译运行结果
8、使用protect定义属性,本包、其他包的子类可访问
Mymath.java
package b;
//public 表示能访问这个类,但是能不能访问类的成员取决于成员的权限
public class Mymath{
protected int x;/* protected:受保护的权限 */
}
Pack.java
package a;
import b.*;
/* 作为 Mymath 子类(b包里面),它里面可以去访问b里面的 protected 成员变量 */
class Mysubmath extends Mymath{
void printInfo(){/* protected 在不同包内只能在子类里面进行访问,同包的话就没有限制 */
System.out.println("Mysubmath: x = " + x);/* 访问 b 包里面 Mymath 类的 x1 这个成员,毫无问题 */
}
}
public class Pack{
public static void main(String args[]){
Mysubmath m = new Mysubmath();
//m.x = 0; //m.x1 = 0;//protected只能在不同包的子类可以调用,这不是子类,错误
m.printInfo();//这里只能通过本包子类的方法间接去调用
}
}
编译运行结果
类的成员权限如果为“default”,如下:
package a;
class Mymath{
int x1;/* 默认权限:default */
}
再有一个同包的类,如下
package a;//这个类也放到a目录(包)里面
public class Pack{
public static void main(String args[]) {
Mymath m = new Mymath();
/* 下面这一步没有问题,因为 defualt 权限同一个包内能访问,但不同包内不行 */
m.x1 = 0;
}
}
解压是jar