Certification Objective Declare Classes (Exam Objective 1.1)


Certification Objective —Declare Classes (Exam Objective 1.1)

1.1 Develop code that declares classes (including abstract and all forms of nested classes), interfaces, and enums, and includes the appropriate use of package and import statements (including static imports).

When you write code in Java, you're writing classes or interfaces. Within those classes, as you know, are variables and methods (plus a few other things). How you declare your classes, methods, and variables dramatically affects your code's behavior. For example, a public method can be accessed from code running anywhere in your application, Mark that method private, though, and it vanishes from everyone's radar (except the class in which it was declared). For this objective, we'll study the ways in which you can declare and modify (or not) a class. You'll find that we cover modifiers in an extreme level of detail, and though we know you're already familiar with them, we're starting from the very beginning. Most Java programmers think they know how all the modifiers work, but on closer study often find out that they don't (at least not to the degree needed for the exam). Subtle distinctions are everywhere, so you need to be absolutely certain you're completely solid on everything in this section's objectives before taking the exam.

Source File Declaration Rules

Before we dig into class declarations, let's do a quick review of the rules associated with declaring classes, import statements, and package statements in a source file:

  • There can be only one public class per source code file.

  • Comments can appear at the beginning or end of any line in the source code file; they are independent of any of the positioning rules discussed here.

  • If there is a public class in a file, the name of the file must match the name of the public class. For example, a class declared as public class Dog { } must be in a source code file named Dog.java.

  • If the class is part of a package, the package statement must be the first line in the source code file, before any import statements that may be present.

  • If there are import statements, they must go between the package statement (if there is one) and the class declaration. If there isn't a package statement, then the import statement(s) must be the first line(s) in the source code file. If there are no package or import statements, the class declaration must be the first line in the source code file.

  • import and package statements apply to all classes within a source code file. In other words, there's no way to declare multiple classes in a file and have them in different packages, or use different imports.

  • A file can have more than one nonpublic class.

  • Files with no public classes can have a name that does not match any of the classes in the file.

In Chapter 10 we'll go into a lot more detail about the rules involved with declaring and using imports, packages, and a feature new to Java 5, static imports.

Class Declarations and Modifiers

Although nested (often called inner) classes are on the exam, we'll save nested class declarations for Chapter 8. You're going to love that chapter. No, really. Seriously. The following code is a bare-bones class declaration:

 class MyClass { } 

This code compiles just fine, but you can also add modifiers before the class declaration. Modifiers fall into two categories:

  • Access modifiers: public, protected, private.

  • Non-access modifiers (including strictfp, final, and abstract).

We'll look at access modifiers first, so you'll learn how to restrict or allow access to a class you create. Access control in Java is a little tricky because there are four access controls (levels of access) but only three access modifiers. The fourth access control level (called default or package access) is what you get when you don't use any of the three access modifiers. In other words, every class, method, and instance variable you declare has an access control, whether you explicitly type one or not. Although all four access controls (which means all three modifiers) work for most method and variable declarations, a class can be declared with only public or default access; the other two access control levels don't make sense for a class, as you'll see.

On the Job 

Java is a package-centric language; the developers assumed that for good organization and name scoping, you would put all your classes into packages. They were right, and you should. Imagine this nightmare: Three different programmers, in the same company but working on different parts of a project, write a class named utilities. If those three utilities classes have not been declared in any explicit package, and are in the classpath, you won't have any way to tell the compiler or JVM which of the three you're trying to reference. Sun recommends that developers use reverse domain names, appended with division and/or project names. For example, if your domain name is geeksanonymous.com, and you're working on the client code for the TwelvePointOSteps program, you would name your package something like com.geeksanonymous.steps.client. That would essentially change the name of your class to com.geeksanonymous.steps.client.Utilities. You might still have name collisions within your company, if you don't come up with your own naming schemes, but you're guaranteed not to collide with classes developed outside your company (assuming they follow Sun's naming convention, and if they don't, well, Really Bad Things could happen).

Class Access

What does it mean to access a class? When we say code from one class (class A) has access to another class (class B), it means class A can do one of three things:

  • Create an instance of class B.

  • Extend class B (in other words, become a subclass of class B).

  • Access certain methods and variables within class B, depending on the access control of those methods and variables.

In effect, access means visibility. If class A can't see class B, the access level of the methods and variables within class B won't matter; class A won't have any way to access those methods and variables.

Default Access A class with default access has no modifier preceding it in the declaration! It's the access control you get when you don't type a modifier in the class declaration. Think of default access as package-level access, because a class with default access can be seen only by classes within the same package. For example, if class A and class B are in different packages, and class A has default access, class B won't be able to create an instance of class A, or even declare a variable or return type of class A. In fact, class B has to pretend that class A doesn't even exist, or the compiler will complain. Look at the following source file:

 package cert; class Beverage { } 

Now look at the second source file:

 package exam.stuff; import cert.Beverage; class Tea extends Beverage { } 

As you can see, the superclass (Beverage) is in a different package from the subclass (Tea). The import statement at the top of the Tea file is trying (fingers crossed) to import the Beverage class. The Beverage file compiles fine, but when we try to compile the Tea file we get something like:

 Can't access class cert.Beverage. Class or interface must be public, in same package, or an accessible member class. import cert.Beverage; 

Tea won't compile because its superclass, Beverage, has default access and is in a different package. Apart from using fully qualified class names, which we'll cover in Chapter 10, you can do one of two things to make this work. You could put both classes in the same package, or you could declare Beverage as public, as the next section describes.

When you see a question with complex logic, be sure to look at the access modifiers first. That way, if you spot an access violation (for example, a class in package A trying to access a default class in package B), you'll know the code won't compile so you don't have to bother working through the logic. It's not as if you don't have anything better to do with your time while taking the exam. Just choose the "Compilation fails" answer and zoom on to the next question.

Public Access A class declaration with the public keyword gives all classes from all packages access to the public class. In other words, all classes in the Java Universe (JU) have access to a public class. Don't forget, though, that if a public class you're trying to use is in a different package from the class you're writing, you'll still need to import the public class.

In the example from the preceding section, we may not want to place the subclass in the same package as the superclass. To make the code work, we need to add the keyword public in front of the superclass (Beverage) declaration, as follows:

 package cert; public class Beverage { } 

This changes the Beverage class so it will be visible to all classes in all packages. The class can now be instantiated from all other classes, and any class is now free to subclass (extend from) it—unless, that is, the class is also marked with the nonaccess modifier final. Read on.

Other (Nonaccess) Class Modifiers

You can modify a class declaration using the keyword final, abstract, or strictfp. These modifiers are in addition to whatever access control is on the class, so you could, for example, declare a class as both public and final. But you can't always mix nonaccess modifiers. You're free to use strictfp in combination with final, for example, but you must never, ever, ever mark a class as both final and abstract. You'll see why in the next two sections.

You won't need to know how strictfp works, so we're focusing only on modifying a class as final or abstract. For the exam, you need to know only that strictfp is a keyword and can be used to modify a class or a method, but never a variable. Marking a class as strictfp means that any method code in the class will conform to the IEEE 754 standard rules for floating points. Without that modifier, floating points used in the methods might behave in a platform-dependent way. If you don't declare a class as strictfp, you can still get strictfp behavior on a method-by-method basis, by declaring a method as strictfp. If you don't know the IEEE 754 standard, now's not the time to learn it. You have, as we say, bigger fish to fry.

Final Classes When used in a class declaration, the final keyword means the class can't be subclassed. In other words, no other class can ever extend (inherit from) a final class, and any attempts to do so will give you a compiler error.

So why would you ever mark a class final? After all, doesn't that violate the whole object-oriented (OO) notion of inheritance? You should make a final class only if you need an absolute guarantee that none of the methods in that class will ever be overridden. If you're deeply dependent on the implementations of certain methods, then using final gives you the security that nobody can change the implementation out from under you.

You'll notice many classes in the Java core libraries are final. For example, the string class cannot be subclassed. Imagine the havoc if you couldn't guarantee how a string object would work on any given system your application is running on! If programmers were free to extend the string class (and thus substitute their new string subclass instances where java.lang.String instances are expected), civilization—as we know it—could collapse. So use final for safety, but only when you're certain that your final class has indeed said all that ever needs to be said in its methods. Marking a class final means, in essence, your class can't ever be improved upon, or even specialized, by another programmer.

A benefit of having nonfinal classes is this scenario: Imagine you find a problem with a method in a class you're using, but you don't have the source code. So you can't modify the source to improve the method, but you can extend the class and override the method in your new subclass, and substitute the subclass everywhere the original superclass is expected. If the class is final, though, then you're stuck.

Let's modify our Beverage example by placing the keyword final in the declaration:

 package cert; public final class Beverage {   public void importantMethod() { } } 

Now, if we try to compile the Tea subclass:

 package exam.stuff; import cert.Beverage; class Tea extends Beverage { } 

We get an error something like

 Can't subclass final classes: class cert.Beverage class Tea extends Beverage{ 1 error 

In practice, you'll almost never make a final class. A final class obliterates a key benefit of OO—extensibility. So unless you have a serious safety or security issue, assume that some day another programmer will need to extend your class. If you don't, the next programmer forced to maintain your code will hunt you down and <insert really scary thing>.

Abstract Classes An abstract class can never be instantiated, Its sole purpose, mission in life, raison d'être, is to be extended (subclassed). (Note, however, that you can compile and execute an abstract class, as long as you don't try to make an instance of it. ) Why make a class if you can't make objects out of it? Because the class might be just too, well, abstract. For example, imagine you have a class Car that has generic methods common to all vehicles. But you don't want anyone actually creating a generic, abstract car object. How would they initialize its state? What color would it be? How many seats? Horsepower? All-wheel drive? Or more importantly, how would it behave? In other words, how would the methods be implemented?

No, you need programmers to instantiate actual car types such as BMWBoxster and Subaruoutback. We'll bet the Boxster owner will tell you his car does things the Subaru can do "only in its dreams." Take a look at the following abstract class:

 abstract class Car {    private double price;    private String model;    private String year;    public abstract void goFast();    public abstract void goUpHill();    public abstract void impressNeighbors();    // Additional, important, and serious code goes here } 

The preceding code will compile fine. However, if you try to instantiate a Car in another body of code, you'll get a compiler error something like this:

 AnotherClass.java:7: class Car is an abstract class. It can't be instantiated.       Car x = new Car(); 1 error 

Notice that the methods marked abstract end in a semicolon rather than curly braces.

Look for questions with a method declaration that ends with a semicolon, rather than curly braces. If the method is in a class—as opposed to an interface—then both the method and the class must be marked abstract. You might get a question that asks how you could fix a code sample that includes a method ending in a semicolon, but without an abstract modifier on the class or method. In that case, you could either mark the method and class abstract, or change the semicolon to code (like a curly brace pair). Remember, if you change a method from abstract to nonabstract, don't forget to change the semicolon at the end of the method declaration into a curly brace pair!

We'll look at abstract methods in more detail later in this objective, but always remember that if even a single method is abstract, the whole class must be declared abstract. One abstract method spoils the whole bunch. You can, however, put nonabstract methods in an abstract class. For example, you might have methods with implementations that shouldn't change from Car type to Car type, such as getColor() or setPrice(). By putting nonabstract methods in an abstract class, you give all concrete subclasses (concrete just means not abstract) inherited method implementations. The good news there is that concrete subclasses get to inherit functionality, and need to implement only the methods that define subclass specific behavior.

(By the way, if you think we misused raison d'être earlier, don't send an e-mail. We'd like to see you work it into a programmer certification book.)

Coding with abstract class types (including interfaces, discussed later in this chapter) lets you take advantage of polymorphism, and gives you the greatest degree of flexibility and extensibility. You'll learn more about polymorphism in Chapter 2.

You can't mark a class as both abstract and final. They have nearly opposite meanings. An abstract class must be subclassed, whereas a final class must not be subclassed. If you see this combination of abstract and final modifiers, used for a class or method declaration, the code will not compile.

Exercise 1-1: Creating an Abstract Superclass and Concrete Subclass

image from book

The following exercise will test your knowledge of public, default, final, and abstract classes. Create an abstract superclass named Fruit and a concrete subclass named Apple. The superclass should belong to a package called food and the subclass can belong to the default package (meaning it isn't put into a package explicitly). Make the superclass public and give the subclass default access.

  1. Create the superclass as follows:

     package food; public abstract class Fruit{ /* any code you want */} 

  2. Create the subclass in a separate file as follows:

     import food.Fruit; class Apple extends Fruit{ /* any code you want */} 

  3. Create a directory called food off the directory in your class path setting.

  4. Attempt to compile the two files. If you want to use the Apple class, make sure you place the Fruit.class file in the food subdirectory.

image from book




SCJP Sun Certified Programmer for Java 5 Study Guide Exam 310-055
SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055) (Certification Press)
ISBN: 0072253606
EAN: 2147483647
Year: 2006
Pages: 131

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