Previous | Table of Contents | Next |
Name conflicts are a major problem when developing reusable code. No matter how carefully you pick names for classes and methods, somebody else is likely to use that name for a different purpose. If you use simple, descriptive names, the problem gets worsesuch names are more likely to be used by someone else who was also trying to use simple, descriptive names. Words like set, get, clear, and so on, are used a lot and are almost certain to clash with other peoples uses.
The standard solution for name collision in many programming languages is to use a package prefix at the front of every class, type, global function, and so on. Prefix conventions create naming contexts to ensure that names in one package do not conflict with names in other packages. These prefixes are usually a few characters long and are usually an abbreviation of the package product name, such as Xt for X Toolkit, or WIN32 for the 32-bit Windows API.
When code uses only a few packages, the likelihood of prefix conflict is small. However, since prefixes are abbreviations, the probability of a name conflict increases with the number of packages used.
Java has adopted a more formal notion of packages that has a set of types and subpackages as members. Packages are named and can be imported. Package names are hierarchical, with components separated by dots. When you use part of a package, either you use its fully qualified name, or you import all or part of the package. Hierarchical package names enable longer package names. Hierarchical package names also give you control over name conflictsif two packages contain classes with the same name, you can use a package-qualified form of the class name for one or both of them.
Here is an example of a method that uses fully qualified names to print the current day and time using Javas utility class Date:
class Date1 { public static void main(String[] args) { java.util.Date now = new java.util.Date(); System.out.println(now); } }
And here is a version that uses import to declare the type Date:
import java.util.Date; class Date2 { public static void main(String[] args) { Date now = new Date(); System.out.println(now); } }
The name-collision problem is not completely solved by the Java package mechanism. Two projects can still give their packages the same name. This problem can be solved only by convention. The standard convention is to use the reversed Internet domain name of the organization to prefix the package name. For example, if the Acme Corporation had the Internet domain acme.com, it would use package names of the form COM.acme.package.
Having dots separate package components may occasionally cause confusion, because the dot is also used to invoke methods and access fields in object references. This may lead to confusion as to what can be imported. Java novices often try to import System.out so they dont have to type it in front of every println. This does not work because System is a class, in which out is a static field whose type supports the println method.
On the other hand, java.util is a package, so you can import java.util.Date (or java.util.* if you want everything from the package). If you are having problems importing something, setup and make sure that you are importing a type.
Java classes are always in a package. A package is named by providing a package declaration at the top of the source file:
package com.sun.games; class Card { // ... } // ...
If a name is not provided via a package declaration, the class is made part of an unnamed package. Although this is adequate for an application (or applet) that is not loaded with any other code, classes destined for a library should be written in named packages.
Java is designed to maximize portability. Many details about Java are specifically defined for all implementations. For example, an int is a 32-bit twos-complement signed integer. Many languages leave precise definitions to particular implementations, making only general guarantees such as minimum range, or provide a way to ask the system what the range is on the current platform.Java makes these definitions specific all the way down to the machine language into which Java code is translated. Java source code is compiled into Java bytecodes, designed to be run on a Java virtual machine. Bytecodes are a machine language for an abstract machine, but are interpreted by the virtual machine on each system that supports Java.3
3A system can, of course, implement the Java virtual machine in siliconthat is, using a special-purpose chip. This does not affect the portability of the bytecode; it is just another virtual machine implementation.
The virtual machine assigns each application its own runtime, which both isolates applications from each other and provides a security model. Each runtimes security manager decides on the capabilities available to the application. The security manager could, for example, forbid the application from reading or writing the local disk, or allow network connections only to particular machines.
These features combined give Java code complete platform independence to provide a security model suitable for executing code downloaded across the network at varying levels of trust. Java source code compiled into Java bytecodes can be run on any machine with a Java virtual machine. The code can be executed with an appropriate level of protection to prevent careless or malicious class writers from harming the system. The level of trust can be adjusted depending on the source of the bytecodesbytecodes on the local disk or protected network can be trusted more than bytecodes fetched from arbitrary machines elsewhere in the world.
Java has several other features which we mention briefly here:
Previous | Table of Contents | Next |