为什么在Java包中的文件里要写上“package”这个东西?难道如果它在目录里,就不间接地假定它已经在包里了吗?
我来自C++的世界。我总是从使用该类的其他文件中导入需要的类的.h文件(我的意思是,我只想“展示”头文件,而不是实现)。但是现在我对Java中的导入有点困惑。Java中如何实现这一点?
不,这并不是默认假设。毕竟,我的包叫什么?com.mypackage.stuff?src.com.mypackage.stuff?myproject.com.mypackage.stuff?C.Users.makakko.workspace.myproject.src.com.mypackage.stuff?
如果你只根据文件夹来确定包的位置,那么它是相对于驱动器根目录的吗?如果项目在另一台机器上的不同驱动器上开发,会怎样呢?它是相对于javac.exe的位置吗?再说了,如果安装目录不同呢?当运行javac时,工作目录是什么?但是你可以指定一个位置让javac来查找你的源文件。如果你想要编写一个简单的测试程序或者教一个从未编程过的人Java,你必须使用/解释整个包结构的概念吗?
如果你省略package
说明符,那么你仍然处于一个包中。它只是“默认包”,没有名称。
头文件更多地是C编译方式所需的产物,而不是实现信息隐藏的方法。在C中,必须先定义一个方法,然后才能引用它。如果你想要有几个相互引用的方法,你必须在使用任何一个方法之前定义所有方法,因此需要头文件。C++中的头文件继承了这一点,但是C++中的更改改变了头文件的必要性。
在Java中,编译器将在执行任何需要方法/类的操作之前查看所有方法和类的签名。头文件的作用被放入了编译器本身。你不能依赖头文件来实现信息隐藏,因为
代码可以放在头文件中
除非你使用真正的信息隐藏(如单独的库),否则程序员可以找到与头文件匹配的c/cpp文件而没有问题
同样,在Java中,只有通过删除源代码才能获得真正的信息隐藏。一旦你使源代码不可访问,你就会公开公共/受保护的类、枚举和接口的API。为了加分,为每个东西编写解释性的JavaDoc注释,并运行javadoc.exe对你的源代码进行分离的文档生成,以供使用你的包的人使用。
1)package
声明必须与项目中的目录层次结构匹配。
如果我在Car.java
中使用package com.stackoverflow.bakkal;
,则应该遵循以下层次结构。
com/
|-- stackoverflow/
| `-- bakkal/
| |-- Car.java
2) 如果你想要隐藏一个实现,可以在Java中使用interface
代替class
。然后将实际的实现分发在例如.class
文件或JARs中。
嗯,但是接口无法被实例化......
接口在某种程度上类似于C++中的原型。你有合同,然后实际的实现来自其他地方。
我想要实例化一个类,但是不给出实现,只给出原型
即使在C++中也不可能做到这一点,你如何实例化一个没有实际实现的东西呢?在C++中,你仍然需要链接到对象文件。在Java中,你使用.class
文件。
Java的哲学是“显式优于隐式/假定”,因此不会假定包。它确实使你能够访问当前包中的任何内容,但需要明确导入任何外部内容。(我相信Java.lang是一个例外,因为它包含了很多基本功能,例如String,没有一个单独的包不会使用它)。
这也是为什么你倾向于看到:
import java.util.ArrayList;
import java.util.LinkedList;
改为:
import java.util.*;
该包指定了一个类的路径。它必须与磁盘或jar(zip)中的目录相匹配。位置是相对于类路径上的位置。受保护的访问仅限于同一包中的类。
.h文件中可能会做一些在类定义中完成的事情。常量属于一个类,可以公开可见。在.h中,常量必须公开可见。
导入与包含一个.h的效果相同,但帮助处理同名定义冲突的问题。您可以包含一个项目或从一个类中导入所有可见项目。也可以跳过导入,直接使用包名作为前缀来访问所需类。
通过导入不能真正看到实现(至少不超出编译后的类提供的范围)。可见的是可见接口的公共方法和数据。对于来自同一包的导入,未指定访问权限(public/protected/private)的方法和数据也是可见的。受保护的方法和变量对该类的子类可见。.h文件可以在不提供源代码或目标文件的情况下使用。导入要求提供指定的类。(一个类可能只由常量组成,尽管这样设计是不好的。)
protected
访问修饰符表示子类可以访问,但同一包中的其他类不能访问。没有指定任何访问修饰符(public/protected/private)时,使用的是包访问权限(也称为“默认访问权限”)。 - Brian S
com.mypackage.stuff
更改为任何其他名称,并在不更改CLASSPATH
的情况下编译即可。 - maaartinus