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 ...
随机推荐
- 在Android应用中使用OpenGL
Android为OpenGL ES支持提供了GLSurfaceView组件,这个组件用于显示3D图形.GLSurfaceView本身并不提供绘制3D图形的功能,而是由GLSurfaceView.Re ...
- [Js]跟随鼠标移动的div
例子:鼠标移动到一块东西上,出现提示文本框,并且提示文本框跟着鼠标的位置动 document.onmouseover=function(ev){ var oEvent=ev||event; var b ...
- OL/SQL编程练习
create or replace procedure pr_first is --一个变量 v_a ) := '总有一天我的生命将走到尽头'; --一个常量 c_b constant ) := '而 ...
- 2.精通前端系列技术之JavaScript模块化开发 seajs(一)
在使用seajs模块化开发之前,直接在页面引用js会容易出现冲突及依赖相关的问题,具体问题如下 问题1:多人开发脚本的时候容易产生冲突(比如全局参数冲突,方法名冲突),可以使用命名空间降低冲突,不能完 ...
- zoj 3228 覆盖及非覆盖串的多次匹配
题目题意: 给定多个小串,在一个长串中寻找这些串的匹配次数,有些统计的是可覆盖的,有些统计的是非覆盖的 先可以简单理解一下,建立ac自动机后,当前节点包含的字符串必然被把它作为fail指针的节点包含, ...
- 如何在redhat下安装办公软件(openoffice)
在redhat的client版本中自带有办公软件libreoffice,而在server版的redhat中却没有自带的办公软件,那么,如何在redhat的server版下安装办公软件呢? 方法一:配置 ...
- 'NSInteger' (aka 'long') to 'int32
怎么去掉Xcode工程中的某种类型的警告 Implicit conversion loses integer precision: 'NSInteger' (aka 'long') to 'int32 ...
- 最大子段和-Program A
最大子段和 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Description G ...
- CCNA 6.9
page 201 show ip route Correction(05-4) Basic configuration of R1: enable configure terminal ...
- IOS打开其他应用、以及被其他应用打开
1.打开其他应用 appURLStr = "cwork://app_id?title=xxx&content=xxx" [[UIApplication sharedAppl ...