Core Java Volume I — 4.7. Packages
4.7. Packages
Java allows you to group classes in a collection called a package. Packages are convenient for organizing your work and for separating your work from code libraries provided by others.
The standard Java library is distributed over a number of packages, including java.lang, java.util, java.net, and so on. The standard Java packages are examples of hierarchical packages. Just as you have nested subdirectories on your hard disk, you can organize packages by using levels of nesting. All standard Java packages are inside the java and javax package hierarchies.
The main reason for using packages is to guarantee the uniqueness of class names. Suppose two programmers come up with the bright idea of supplying an Employee class. As long as both of them place their class into different packages, there is no conflict. In fact, to absolutely guarantee a unique package name, use an Internet domain name (which is known to be unique) written in reverse. You then use subpackages for different projects. For example, horstmann.com is a domain that one of the authors registered. Written in reverse order, it turns into the package com.horstmann. That package can then be further subdivided into subpackages such as om.horstmann.corejava.
From the point of view of the compiler, there is absolutely no relationship between nested packages. For example, the packages java.util and java.util.jar have nothing to do with each other. Each is its own independent collection of classes.
4.7.1. Class Importation
A class can use all classes from its own package and all public classes from other packages(一个类可以使用同一个包中的所有类,也可以使用其他包中的公有类).
You can access the public classes in another package in two ways. The first is simply to add the full package name in front of every class name. For example:
java.util.Date today = new java.util.Date();
That is obviously tedious. The simpler, and more common, approach is to use the import statement. The point of the import statement is to give you a shorthand to refer to the classes in the package. Once you use import, you no longer have to give the classes their full names.
You can import a specific class or the whole package. You place import statements at the top of your source files (but below any package statements). For example, you can import all classes in the java.util package with the statement
import java.util.*;
Then you can use
Date today = new Date();
without a package prefix. You can also import a specific class inside a package:
import java.util.Date;
The java.util.* syntax is less tedious. It has no negative effect on code size.
However, if you import classes explicitly, the reader of your code knows exactly which classes you use.
Tip
In Eclipse, you can select the menu option Source -> Organize Imports.
Package statements such as import java.util.*; are automatically expanded
into a list of specific imports such as
import java.util.ArrayList;
import java.util.Date;
This is an extremely convenient feature.
However, note that you can only use the * notation to import a single package. You cannot use import java.* or import java.*.* to import all packages with the java prefix.
Most of the time, you just import the packages that you need, without worrying too much about them. The only time that you need to pay attention to packages is when you have a name conflict. For example, both the java.util and java.sql packages have a Date class. Suppose you write a program that imports both packages.
import java.util.*;
import java.sql.*;
If you now use the Date class, you get a compile-time error:
Date today; // ERROR--java.util.Date or java.sql.Date?
The compiler cannot figure out which Date class you want. You can solve this problem by adding a specific import statement:
import java.util.*;
import java.sql.*;
import java.util.Date;
What if you really need both Date classes? Then you need to use the full package name with every class name.
java.util.Date deadline = new java.util.Date();
java.sql.Date today = new java.sql.Date(...);
Locating classes in packages is an activity of the compiler. The bytecodes in class files always use full package names to refer to other classes.
C++ Note
C++ programmers sometimes confuse import with #include. The two have nothing in common. In C++, you must use #include to include the declarations of external features because the C++ compiler does not look inside any files
except the one that it is compiling and its explicitly included header files. The Java compiler will happily look inside other files provided you tell it where to look.
In Java, you can entirely avoid the import mechanism by explicitly naming all classes, such as java.util.Date. In C++, you cannot avoid the #include directives.
The only benefit of the import statement is convenience. You can refer to a class by a name shorter than the full package name. For example, after an import java.util.* (or import java.util.Date) statement, you can refer to
the java.util.Date class simply as Date.
In C++, the construction analogous to the package mechanism is the namespace feature. Think of the package and import statements in Java as the analogs of the namespace and using directives in C++.
4.7.2. Static Imports
A form of the import statement permits the importing of static methods and fields, not just classes.
For example, if you add the directive
import static java.lang.System.*;
to the top of your source file, then you can use the static methods and fields of the System class without the class name prefix:
out.println("Goodbye, World!"); // i.e., System.out
exit(0); // i.e., System.exit
You can also import a specific method or field:
import static java.lang.System.out;
In practice, it seems doubtful that many programmers will want to abbreviate System.out or System.exit. The resulting code seems less clear. On the other hand,
sqrt(pow(x, 2) + pow(y, 2))
seems much clearer than
Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2))
4.7.3. Addition of a Class into a Package
To place classes inside a package, you must put the name of the package at the top of your source file, before the code that defines the classes in the package. For example, the file Employee.java in Listing 4.7 starts out like this:
package com.horstmann.corejava;
public class Employee
{
. . .
}
If you don't put a package statement in the source file, then the classes in that source file belong to the default package. The default package has no package name. Up to now, all our example classes were located in the default package.
Place source files into a subdirectory that matches the full package name. For example, all source files in the package com.horstmann.corejava package should be in a subdirectory com/horstmann/corejava (com\horstmann\corejava on Windows). The compiler places the class files into the same directory structure.
The program in Listings 4.6 and 4.7 is distributed over two packages: The PackageTest class belongs to the default package, and the Employee class belongs to the com.horstmann.corejava package. Therefore, the Employee.java file must be in a subdirectory com/horstmann/corejava. In other words, the directory structure is as follows:
To compile this program, simply change to the base directory and run the command
javac PackageTest.java
The compiler automatically finds the file com/horstmann/corejava/Employee.java and compiles it.
Let's look at a more realistic example, in which we don't use the default package but have classes distributed over several packages (com.horstmann.corejava and com.mycompany).
In this situation, you still must compile and run classes from the base directory, that is, the directory containing the com directory:
javac com/mycompany/PayrollApp.java
java com.mycompany.PayrollApp
Note again that the compiler operates on files (with file separators and an extension .java), whereas the Java interpreter loads a class (with dot separators).
Tip
Starting with the next chapter, we will use packages for the source code. That way, you can make an IDE project for each chapter instead of each section.
Caution
The compiler does not check the directory structure when it compiles source files. For example, suppose you have a source file that starts with the directive package com.mycompany;
You can compile the file even if it is not contained in a subdirectory com/mycompany. The source file will compile without errors if it doesn't depend on other packages. However, the resulting program will not run. The virtual
machine won't find the resulting classes when you try to run the program.
4.7.4. Package Scope
You have already encountered the access modifiers public and private. Features tagged as public can be used by any class. Private features can be used only by the class that defines them. If you don't specify either public or private, the feature (that is, the class, method, or variable) can be accessed by all methods in the same package.
Consider the program in Listing 4.2 on p. 146. The Employee class was not defined as a public class. Therefore, only the other classes (such as EmployeeTest) in the same package—the default package in this case—can access it. For classes, this is a reasonable default. However, for variables, this was an unfortunate choice. Variables must explicitly be marked private, or they will default to being package-visible. This, of course, breaks encapsulation. The problem is that it is awfully easy to forget to type the private keyword. Here is an example from the Window class in the java.awt package, which is part of the source code supplied with the JDK:
public class Window extends Container
{
String warningString;
. . .
}
Note that the warningString variable is not private! That means the methods of all classes in the java.awt package can access this variable and set it to whatever they like (such as "Trust me!"). Actually, the only methods that access this variable are in the Window class, so it would have been entirely appropriate to make the variable private.
We suspect that the programmer typed the code in a hurry and simply forgot the private modifier. (We won't mention the programmer's name to protect the guilty—you can look into the source file yourself.)
Note
Amazingly enough, this problem has never been fixed, even though we have pointed it out in eight editions of this book—apparently the library implementors don't read Core Java. Not only that—new fields have been added to the class over time, and about half of them aren't private either.
Is this really a problem? It depends. By default, packages are not closed entities. That is, anyone can add more classes to a package. Of course, hostile or clueless programmers can then add code that modifies variables with package visibility. For example, in early versions of Java, it was an easy matter to smuggle another class into the java.awt package. Simply start out the class with package java.awt;
Then, place the resulting class file inside a subdirectory java/awt somewhere on the class path, and you have gained access to the internals of the java.awt package.
Through this subterfuge, it was possible to set the warning string (see Figure 4.9).
Figure 4.9. Changing the warning string in an applet window
Starting with version 1.2, the JDK implementors rigged the class loader to explicitly disallow loading of user-defined classes whose package name starts with "java.". Of course, your own classes won't benefit from that protection. Instead, you can use another mechanism, package sealing, to address the issue of promiscuous package access. If you seal a package, no further classes can be added to it. You will see in Chapter 10 how you can produce a JAR file that contains sealed packages.
Core Java Volume I — 4.7. Packages的更多相关文章
- Core Java Volume I — 1.2. The Java "White Paper" Buzzwords
1.2. The Java "White Paper" BuzzwordsThe authors of Java have written an influential White ...
- Core Java Volume I — 3.10. Arrays
3.10. ArraysAn array is a data structure that stores a collection of values of the same type. You ac ...
- Core Java Volume I — 3.8. Control Flow
3.8. Control FlowJava, like any programming language, supports both conditional statements and loops ...
- Core Java Volume I — 5.1. Classes, Superclasses, and Subclasses
5.1. Classes, Superclasses, and SubclassesLet's return to the Employee class that we discussed in th ...
- Core Java Volume I — 4.10. Class Design Hints
4.10. Class Design HintsWithout trying to be comprehensive or tedious, we want to end this chapter w ...
- Core Java Volume I — 4.6. Object Construction
4.6. Object ConstructionYou have seen how to write simple constructors that define the initial state ...
- Core Java Volume I — 4.5. Method Parameters
4.5. Method ParametersLet us review the computer science terms that describe how parameters can be p ...
- Core Java Volume I — 4.4. Static Fields and Methods
4.4. Static Fields and MethodsIn all sample programs that you have seen, the main method is tagged w ...
- Core Java Volume I — 4.1. Introduction to Object-Oriented Programming
4.1. Introduction to Object-Oriented ProgrammingObject-oriented programming, or OOP for short, is th ...
随机推荐
- RAID在数据库存储上的应用-转
随着单块磁盘在数据安全.性能.容量上呈现出的局限,磁盘阵列(Redundant Arrays of Inexpensive/Independent Disks,RAID)出现了,RAID把多块独立的磁 ...
- 一个简单的excel文件上传到数据库方法
因为以前项目中有用到过Excel导入,所以整理了一下,这是一个导入Excel数据到数据库的方法 注意:需要导入poi jar包 代码清单 /** * Excel 导入 * @param mapping ...
- 查询使用NoLock
当我们在操作数据库的时候,无论是查询还是修改数据库的操作我们都习惯使用using(var db=new XXXDB()){},但是如果仅仅是做查询,最好是使用NoLock,因为NoLock使用的是共享 ...
- HTML5表单新增属性
1.form 原来html里面,表单里的元素应该包裹在表单里,如 <form action="login.php" method="get"> &l ...
- [Js]Ajax
一.什么是Ajax 不刷新的情况下读取数据或提交数据 (最早出现ajax:谷歌地图,拖动一下出现一片新的视野) 应用:用户注册.在线聊天.微博 特性:只能从服务器上去读取数据(所以我们需要配置自己的服 ...
- UTF-8
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码.由Ken Thompson于1992年创建.现在已经标准化为 ...
- CodeIgniter 引入自定义公共函数
CodeIgniter 中公共函数不能追加,可以通过 helper 辅助函数实现. 创建 common_helper.php 文件,定义所需公共函数,存放至 application/helpers 目 ...
- EntityFramework查询oracle数据库时报ora-12704: character set mismatch
1.这段linq,执行期间报ora-12704:character set mismatch错误. var query = from m in ctx.MENU where (m.SUPER_MENU ...
- CSS盒子模型和IE浏览器
CSS盒模型图解 下面是一幅关于应用了CSS的元素是如何显示它的尺寸的图示. 在本篇文章中,所有的浏览器在计算盒模型总宽度时处理margin属性的方式都是一致的,所以我们将更多的精力放在padding ...
- initWithFrame 和 initWithCoder
当我们所写的程序里没用用Nib文件(XIB)时,用代码控制视图内容,需要调用initWithFrame去初始化 - (id)initWithFrame:(CGRect)frame { if (self ...