< Zurück | Inhalt | Weiter >

3.4.3 Polymorphism

Polymorphism (from the Greek poly meaning “many” and morph meaning “shape”) refers to the language’s ability to deal with objects of many different “shapes,” that is, classes, as if they were all the same. We have already seen that Java does this via the extends and implements keywords. You can define an interface and then define two classes that both implement this interface.

Remember our Sample class (Example 3.26). We’ll now define another class, Employee, which also implements the Identifiable interface (Example 3.27).



image

Example 3.27 The Employee class

class Employee

extends Person implements Identifiable

{

private int empl_id;


public int getID()

{

return empl_id;

}

}


image


Notice that the same method, getID(), is implemented in the Employee class, but that the field from which it gets the ID value is a different field. That’s implementation-specific—the interface defines only the methods that can be called but not their internal implementation. The Employee class not only implements Identifiable, but it also extends the Person class, so we better show you what our example Person class looks like (Example 3.28).

To make a really useful Person class would take a lot more code than we need for our example. The important part for our example is only that it is quite different from the Sample class we saw earlier.

Example 3.29 demonstrates the use of polymorphism. We only show some small relevant snippets of code; there would be a lot more code for this to be- come an entire, complete example. Don’t be distracted by the constructors; we made up some new ones just for this example, that aren’t in the class definitions above. Can you see where the polymorphism is at work?


image

Example 3.28 The Person class

class Person

{

String name;

Address addr;


public

Person(String name, Address addr)

{

this.name = name; this.addr = addr;


} // constructor

// ... lots more code is here public String getName()

{

return name;

}

}


image


image

Example 3.29 An example use of polymorphism

//...

Sample labwork = new Sample(petridish); Employee tech = new Employee(newguy, 27); Identifiable stuff;


//...

if (mode) {

stuff = labwork;

} else {

stuff = tech;

}

id = stuff.getID();


image


The key point here is when the call is made to getID(). The compiler can’t know at compile time which object will be referred to by stuff, so it doesn’t know whose getID() method will be called. But don’t worry—it works

3.5 O, Templates! Where Art Thou? 93

image


this all out at runtime. That’s polymorphism—Java can deal with these different objects while you, the programmer, can describe them in a generalized way.

One other related keyword should be mentioned here, abstract. When one declares a class as an abstract class, then the class itself is an incomplete definition. With an abstract class you define all the data of the class but need only write method declarations, not necessarily all the code for the methods. This makes abstract classes similar to interfaces, but in an abstract class, some of the methods can be fully written out.

If you’d like to know more about polymorphism, “late binding,” and more of this aspect of Java, read Chapter 7 of Eckel’s Thinking in Java. There is an extensive example there with much more detail than we can cover here.


3.5 O, TEMPLATES! WHERE ART THOU?


image

Programmers familiar with C++ may be wondering how in the world an OOP language without templates can be useful.



NOTE

Actually, something very much like templates is available in Java 5.0.14 A new feature, which Sun calls generics, looks an awful lot like C++ templates (including similar syntax). It provides compile-time type checking and implicit casting when retrieving objects from a generic container.


Speaking as programmers who worked with C++ before it had templates, we can sympathize. Java’s previous lack of true templates does impose some limits on generic programming, but not as much as one might think. Remem- ber that unlike C++, all Java classes inherit from exactly one base class, and that if no base class is specified, they extend the Object class. This means that every single Java class either directly or indirectly extends Object, and thus all Java classes are instances of Object. So if you need, for example, to implement a container, you can guarantee that it can contain any Java class by implementing a container for the Object type. Java also has runtime type identification fea- tures that are more than a match for anything C++ has, plus it has type-safe


image

14. Java 5.0 will only be out by the time this book is completed.


downcasting15 so that in the worst case scenario, your program has a nice, clean type exception. You simply do not get the kind of “mystery bugs” that you can get in C++ when you miscast an object.16

Thanks to interfaces and a true single object hierarchy, many of the uses of C++ templates go away. We doubt very much that you will miss them. In many cases, such as STL algorithms and other functional programming imple- mentations, you can use interfaces to produce similar results.

Critics of the Java language have a point when they complain that all the type casting of class references in order to expose desired interfaces tends to produce code that violates object-oriented principles. The fact that a class or interface implements all these other named interfaces is hard-coded all over the place in an application’s code. Such critics say this is a bad thing, because it vi- olates encapsulation and implementation hiding. These critics have a point. If you find yourself frequently downcasting object references, consider using the Java 5.0 generics, or try to find another way to code what you want to do. There may be a better way. In defense of the original Java approach (before generics), all casts are runtime type safe. An exception is thrown if a class refer- ence is improperly cast. In C++, if you miscast a pointer, it assumes you meant it. Java certainly can be awkward, but errors will get caught. Sometimes that is more important.


3.6 VIRTUALLY FINAL


One difficulty anyone writing about Java faces is whether or not to assume your readers are familiar with C++. In this chapter, we have tried to help those with C++ experience without requiring such knowledge. But it is in the inevitable comparisons between those languages that many subtle Java features are best discussed. We promised you that we would talk about the relative merits of virtual (a C++ concept) and final (a Java concept). To do that, we have to assume some knowledge of C++. So, let’s reverse the pattern and talk about the


image

15. Don’t worry if this is all gibberish to you right now. We will revisit these topics in detail when we come upon them in the course of our sample project.

16. Actually, we’re being a bit optimistic here. While Java programs are not subject to many mystery bugs, the Java Virtual Machines that run Java code are written in traditional languages, and there have been VMs with bugs. Time and again we see that there is no “silver bullet.” But in our experience, Java comes close. So very close.

3.8 Review 95

image


straight Java facts so we can let the non-C++ folks move on while we go a little deeper with you C++’ers.

In Java, a method or a class may be declared final. A method that is de- clared final may not be overridden in classes that extend the class containing the final implementation. A class that is declared final may not be extended at all.

Now, the comparisons to C++ require us to talk about a language feature that does not exist at all in Java. In C++, unless a method is declared virtual, when a class is used by reference to a base class (for example, when using Employee as a Person), the base class version of the method is called. If the method is declared virtual, the version of the method called is the version for the type of Person referenced (in this case, Employee). In Java, all methods are virtual. There is no such keyword in Java.


3.7 A USEFUL SIMPLE APPLICATION


We will use the sample application shown in Example 3.30 in other sections of this book to illustrate the use of Java tools. This example is so simple (a single class) that it doesn’t demonstrate the object-oriented aspect of development, but it does make use of some APIs that take advantage of it. We will not walk you through this application right here, but present it as a listing of a complete Java class. Not all of the APIs used in this example will be explained, so you may want to refer to the Javadoc pages for explanations of object types or method calls that don’t seem obvious.


3.8 REVIEW


We’ve taken a very quick look at the syntax of Java statements, classes, and interfaces. Much of the syntax is very reminiscent of C, though Java’s object- oriented features differ in significant ways from C++. We looked at how to put Java classes into packages, and at the implications of this for locating the

.class files.

We also showed what the HTML-based Javadoc documentation looks like. These HTML pages will likely be a handy reference for you as you design and write your Java code.


image

Example 3.30 Single class example: FetchURL

import java.net.*; import java.io.*;


public class FetchURL { private URL requestedURL;


public FetchURL(String urlName)

{

try {

requestedURL = new URL(urlName);

} catch (Exception e) { e.printStackTrace();

}

}


public String toString()

{

String rc = ""; String line; BufferedReader rdr;


try {

rdr = new BufferedReader( new InputStreamReader(

requestedURL.openConnection().getInputStream()

)

);


while ((line = rdr.readLine()) != null)

{

rc = rc + line + "\n";

}

} catch (Exception e) { e.printStackTrace(); rc = null;

}


return rc;

}

image

3.10 Resources 97

public static void main(String[] args)

{

int i;

FetchURL f;


for (i = 0; i < args.length; i++)

{

System.out.println(args[i] + ":"); System.out.println(new FetchURL(args[i]));

}

}

}


image


3.9 WHAT YOU STILL DONT KNOW


We have deliberately avoided file I/O. For Java, it is a multilayered and complex topic—and with version 1.4 of Java, there is a whole new set of additional classes (java.nio.*) to consider. We refer you instead to Chapter 11 of Eckel’s Thinking in Java.

There are also a few Java keywords that we have not yet discussed, notably

synchronize.

Even if you know all the Java syntax, it may still take a while to get familiar with the way that syntax is typically put to use. Experience and reading other people’s Java code will be your best teachers—but don’t assume that a particular approach is good just because someone else uses it; much new code has been written in the last several years as people have learned Java. Be sure it’s a style worth imitating, and if you find a better way to do it, use it.


3.10 RESOURCES


• Bruce Eckel, Thinking in Java.

• Cay S. Horstmann and Gary Cornell, Core Java 2: Volume 1 Fundamentals, especially Chapter 3.

• John Lewis and William Loftus, Java Software Solutions.

• The Sun Microsystems Java Tutorial.17



image

17. http://java.sun.com/docs/books/tutorial/index.php


3.11 EXERCISES


1. Write a simple class with a main() method that prints out the arguments supplied on the command line used to invoke it. First use a for loop to do this, then a while loop, then a do-while. What differences do you notice? Which do you find most amenable for this task?

2. Modify the previous class to quit echoing its arguments should it en- counter an argument of length 5. (You can tell the length of a String object with the length() method, e.g., mystr.length().) Did you use break, or continue, or some other mechanism?