Data in Interfaces


An interface is allowed to contain data, provided the data is public, final, and static. This provides an easy way to define constant data.

In Chapter 9, "Packages and Access," you looked at static data within a class with the following example:

class Zebra extends Mammal {   static private final double KGS_TO_LBS = 2.2;   . . . } 

The variable KGS_TO_LBS can be used anywhere within the Zebra class. If other classes in the same package want to use the constant, you can declare KGS_TO_LBS to have default access (or even protected access, in which case the other-package subclasses can also use it). The other classes can refer to the constant as Zebra.KGS_TO_LBS. Sometimes this is fine, but in our example it seems to imply that converting from kilograms to pounds has something to do with zebras. If a constant is more properly associated with a package in general, rather than with any individual class, generally it is better to put it in an interface.

For example, you might be creating a package of classes that model the physics of various mutually interacting heavenly bodies. Your package would be called astro, and the classes would be Planet, Star, BlackHole, Comet, and so on. (Their official names would be astro .Planet, astro.Star, astro.BlackHole, and astro.Comet.) The classes probably would all need to use certain fundamental constants, such as the speed of light and the mass of a proton. Let's look at the various options for implementing these.

First, you can avoid the use of constants altogether. Wherever you need the speed of light, use 3.0e8; wherever you need the mass of a proton, use 1.67e-27. As you saw in Chapter 9, this approach is risky. If you type a wrong digit, you'll introduce a bug that can be very hard to find. Moreover, readers of your code might not recognize the significance of 3.0e8 or 1.67e-27 (would you?), so they would not understand the formulas you were implementing.

The next step is to put constants in one of your classes. You might pick Star, arbitrarily, and insert the following lines:

final static double LIGHT_SPEED = 3.0e8; final static double PROTON_MASS = 1.67e-27;

By convention, constants are in all capital letters, with words separated by underscores. Recall that with constants, a typing error results in a variable name that the compiler will not recognize, so you recruit the compiler to help you find typos.

Before we go further, notice that the constant names can be improved on. As they stand, they are truthful but not entirely helpful. 1.66e-27 whats? 3.0e8 whats per what? For optimum clarity, it's best to put the units in the constant names:

final static double LIGHT_SPEED_M_PER_SEC = 3.0e8; final static double PROTON_MASS_KG = 1.67e-27;

That takes a little more typing, but now nobody will ever think the speed of light is expressed in miles per second, or proton mass in micrograms. Within the Star class, you can refer to the constants by name. Elsewhere in the astro package, you can refer to them as Star.LIGHT_SPEED_M_PER_SEC and Star.PROTON_MASS_KG.

This is certainly better than typing literal constants, but it implies that the constants are somehow naturally associated with the class they appear in. You can go one step further by creating an interface for your constants:

package astro; interface AstroConstants {   final static double LIGHT_SPEED_M_PER_SEC = 3.0e8;   final static double PROTON_MASS_KG = 1.67e-27; }

You can also put method declarations in the interface code, but you don't have to. An interface can declare any number of methods, including zero. Now classes in the astro package can refer to AstroConstants.LIGHT_SPEED_M_PER_SEC and AstroConstants.PROTON_MASS_KG. You don't have to pick a class arbitrarily to put your universal constants in.

You can go one step further, because of the following rule: A class that implements an interface can use the constants of that interface by name, without prefixing the interface name. So your BlackHole class could use the following declaration:

package astro; class BlackHole implements AstroConstants {   . . . }

You don't have to do any work to ensure that BlackHole implements all the methods of the interface, because there are no methods in the interface! And now, anywhere within the BlackHole code, and within the code of any other class that implements AstroConstants, you can refer simply to LIGHT_SPEED_M_PER_SEC and PROTON_MASS_KG.

Warning

Beware of a subtlety concerning interfaces. All methods and constants in an interface are public. You can use the public keyword explicitly for clarity, but if you omit it, the interface's features are still public. They do not have default access, which is what you get if you omit an access modifier in the source code for a class. In an earlier example, when you put the constants in class Planet, you didn't use an access modifier. So the constants had default access and could be used anywhere within the astro package, but nowhere else. When you moved the constants to the interface, they were forced to be public. Hence, they were accessible from any code regardless of package.




Ground-Up Java
Ground-Up Java
ISBN: 0782141900
EAN: 2147483647
Year: 2005
Pages: 157
Authors: Philip Heller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net