Java中的包学习笔记

 一、总结

1.引入包的概念的原因和包的作用
比如有多个人开发一个大型程序,A定义了一个 Math.java 类,B也定义了一个 Math.java 类,它们放在不同目录,使用的时候也是用目录来区分,
包实际上就是一个文件夹(可以含有多级子目录)路径名。包的作用就是用来区分同名的类(冲突问题)。

2.使用步骤
package:
Java源文件中:package 包名.子包名;eg: package a.b.c.d;
编译命令:javac -d <dir> <file.java> 表示在<dir>目录下生成包
执行方法:java 包名.子包名.类名

import:
使用不同的包时要import
public class可以被外包访问,class只能在本包中访问(不加public)。
格式:java文件中 import 包名.子包名.类名; 这是手工导入这个类,也可以 import 包名.子包名.*;让JVM自动加载需要的类。

jar:
生成:jar -cvf <file.jar> <dir>
查看:jar -tvf <file.dir>
解压:tar -xvf <file.dir>

3.包就是一个文件夹路径,所以也可以在包下创建类

4.把程序交给用户的时候需要把Pack.class和整个包(a目录)交给他,这样比较麻烦,可以使用jar打包一下. jar -help 查看帮助。

5.压缩成.jar文件后删除a目录后java Pack运行报错“NoClassDefFoundError”,用户找不到这个类了,我们需要设置一个环境变量CLASSPATH,
它有两个作用,一个是在编译的时候来查找源代码,另一个作用是在执行时查找类的路径。
$ export CLASSPATH=.:my.jar //使用 ‘:’ 控制若在当前目录下找不到就去my.jar下面找
然后删除包目录再编译javac Pack.java就可以成功了,执行javac Pack也是成功的。

此时$export CLASSPATH=. 将其设置为默认值,然后重新执行java Pack时就又报错了,说明是实时更加 CLASS_PATH 的值查询的。

如果以后遇到报找不到类的时候就可以考虑是否要设置CLASSPATH。它可以指定目录,也可以指定压缩包。


6.javac -help指明使用 -verbose 可以在编译时输出更多信息,加上它后可以看它去哪里查找那些源代码[search path for source files: .,my.jar]。
显示出的那些目录就是通过CLASS_PATH指定的。
$ javac Pack.java -verbose

7. 多个Java源文件可以 package 在一起,但是一个源文件使用另一个源文件中定义的类还是需要 import <包名>.<类名>

 

二、例子

1. 编译生成包

/*file: Pack.java*/

package a.b.c.d; //要把编译生成的class文件放在指定目录下的a/b/c/d/目录下

public class Pack {
    public static void main(String args[]) {
        System.out.println("Hello, world!");
    }
}

/*
编译执行:
$ javac -d . Pack.java
$ java a.b.c.d.Pack
*/

 

2.区分使用不同包中的函数

$ tree
.
├── lisi
│    └── Math.java
├── Pack.java
└── zhangsan
    ├── Math.java
    └── Print.java

zhangsan/Math.java

package a.b.c.d2;

public class Math {
    public static int sub(int x, int y) {
        return x - y;
    }

    public static int add(int x, int y) {
        return x + y + 2;
    }

}

zhangsan/Print.java

package a.b.c.d2;

public class Print {
    public static void printInfo() {
        System.out.println("package: a.b.c.d2");
    }

}

lisi/Math.java

package a.b.c.d1;

public class Math {
    public static int add(int x, int y) {
        return x + y;
    }
}

Pack.java

import a.b.c.d1.*; //a.b.c.d1.Math
import a.b.c.d2.*; //若这里都直接写a.b.c.d2.Math会报错:Math already defined in a single-type import


public class Pack {
    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方法
        Print.printInfo(); //也可以这样调用,如果没有同名的类的话就不需要使用包来限制它(即使import到类名了,调用函数也需要 类名.函数名()
    }
}

编译执行

javac -d . lisi/Math.java
javac -d . zhangsan/Math.java
javac -d . zhangsan/Print.java

javac Pack.java
javac Pack

 

打包的例子略。

 

2.第二个例子

/*A.java*/
package a.b.c;

public class A {
    public int count;

    protected void print_a() {
        System.out.println("print_a");
    }
}
/*B.java*/
package d.e.f; /*package必须要在import前面*/
import a.b.c.A;

public class B extends A {
    public int count;

    public void print_b() {
        super.print_a(); /*处于不同的包中子类也可以访问父类的protected成员*/
        System.out.println("print_b");
    }
}
/*Test.java*/
package m.n;

import a.b.c.A;
import d.e.f.B;

public class Test {
    public static void main(String args[]) {
        B b = new B();
        b.print_b();
    }
}
/*编译步骤*/
export export CLASSPATH=./
javac -d ./ A.java
javac -d ./ B.java
javac -d ./ Test.java

$ tree
.
├── a
│   └── b
│       └── c
│           └── A.class
├── A.java
├── B.java
├── d
│   └── e
│       └── f
│           └── B.class
├── m
│   └── n
│       └── Test.class
└── Test.java

/*运行和结果*/
$ java m.n.Test 
print_a
print_b

 

三、补充

1. static带实现接口的函数导入

//---------- ITest.java ----------
package a;

public interface ITest {
    public static final int APP_STATUS = 1;static int adjustProcess(String packageName, int status) { System.out.println("Hello"); return 0; }
}


//---------- Test.java ----------
package a;

public class Test implements ITest { //实现接口也继承了接口的成员
    public static int adjustProcess(String packageName, int status) {
        System.out.println("World");
        return 0;
    }
}

//---------- Main.java ---------- 方法1:
package b;

import a.Test;

public class Main {
    public static void main(String args[]) {
        Test.adjustProcess("xiaoming", Test.APP_STATUS);
    }
}
/*
~/tmp/3.java_test/4.array$ javac -d . ITest.java Test.java Main.java
~/tmp/3.java_test/4.array$ java b.Main
World
*/

//---------- Main.java ---------- 方法2:
package b;

import static a.Test.adjustProcess;
import static a.Test.APP_STATUS;

public class Main {
    public static void main(String args[]) {
        adjustProcess("xiaoming", APP_STATUS); //然后直接调用
    }
}

/*
~/tmp/3.java_test/4.array$ javac -d . ITest.java Test.java Main.java
~/tmp/3.java_test/4.array$ java b.Main
World
*/

注: 参考 os.Process.java 的实现。

 

posted on 2019-02-19 00:37  Hello-World3  阅读(156)  评论(0编辑  收藏  举报

导航