|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
General Java Variables Have Types, Objects Have Classes
Variables Have Types, Objects Have Classes
By: Mark Robinson
Apr. 1, 1997 12:00 AM
Last month, I introduced the terms types, variables, classes, objects and references. If you understood the examples and correctly answered the test question I provided at the end of the article, you're well on your way to mastering the essential concepts that govern how all Java programs work. If you missed the article, look for it on SYS-CON's Web site at http://www.JavaDevelopersJournal.com. This month, I'm going to concentrate on eight tenets of Java programming. These tenets are the "truths" that will guide you safely through the darkest complexities of Java syntax as it relates to assignments, casting, constants and method parameters. Here they are: Knowing these tenets will serve you well. To experienced Java programmers, these tenets may be intuitive or even obvious, but they represent fundamental concepts that new Java programmers routinely wrestle with in their attempts to better understand the behaviors (usually error messages) of their programs.
Variables and Types int intVar; declares a new variable named "intVar" that is of type int. The type of a variable limits the values that can be stored in the variable. Since the variable "intVar" was declared to be of type int, it can only hold integer values. Tenet 2 suggests that once you've declared the type of a variable, it can never be changed. Java, in contrast to languages like some of the xBASE derivatives, does not support "un-typed" or "polymorphic" variables that can, for instance, contain an integer value in one part of a program and a character later on. The combination of Tenet 1 and Tenet 2 should make it pretty clear what it means for Java to be a "strongly-typed" language. You cannot, intentionally or otherwise, break the "type" system. Only values that match the declared type of a variable, can be stored in the variable. As I mentioned last month, there are two kinds of types in Java: primitive types and reference types. The primitive types are byte, short, int, long, float, double, char and boolean. The value stored in a variable of a primitive type is the binary representation of a number. The reference types are arrays, classes, and interfaces. As Tenet 3 suggests, the only things that can be stored in variables of a reference type are references. A reference is a value that the Java Virtual Machine utilizes to identify an object. Just as my email address provides you with the means to send messages to me, a reference provides the Java programmer with the means to send messages to an object. In object-oriented programming parlance, "sending a message" to an object is roughly equivalent to calling a function in a non-OOP language. The critical concept to understand is that, in Java, you never deal directly with objects, only with references to objects. Before exploring this further, there are a few points I should cover regarding classes and objects.
Classes Define Types
Animal animalVar;
Creating Objects new Whale(); It may seem self-evident that, in this case, the "class" of the newly created object is Whale. Tenet #4, "The class of an object never changes," just reinforces the fact that no matter what operations are performed, the object itself is never changed or converted to anything else. As long as it exists, its "class" will remain Whale. This leads us to the matter of how long objects exist. An object will continue to exist as long as at least one variable contains a reference to it. Any expression that creates a new object, such as the "new Whale()" statement used above, returns a reference to the object it created. Since, in the above example, I neglected to store the reference that was returned, I lost my opportunity to ever do anything with the object. The newly created object will sit around, inaccessible by the program, until the garbage collector decides to destroy it and reclaim the memory it occupies. Since it is notoriously difficult to do many useful things with objects you can't access, that are prone to disappearing at the whim of the garbage collector, you usually create new objects and assign the returned reference to a variable in a single statement:
whaleVar = new Whale();
Class/Interface Hierarchies Figure 1 illustrates the hierarchy of the classes defined in Listing 1. A class is said to be a subclass of all of the classes from which it is a direct descendant. A class is said to be the superclass of all of the classes which descend from it. Thus, the Animal class is the superclass of all of the classes in Figure 1 except the Object class. Likewise, the Salmon class is a subclass of the Fish class. It is also a subclass of the Animal and Object classes. The words "is/an" can be used to describe the relationship between a subclass and any of its superclasses:
A GoldFish is a Fish OK, so you might not have known that a Dog is an Object. The point is that a subclass is just a more specific type of the class from which it is descended. To generalize, we can substitute the word subtype for the word subclass and the word supertype for the word superclass. Then, as shown in Figure 2, the same description applies to the hierarchical organization of interfaces. Basically, aninterface is a type that is defined by a set of method declarations. It provides a way to overcome some of the limitations that Java programmers face, since a class can have only one direct superclass. As shown in Listing 1, the Fish, GoldFish and Whale classes each implement one of the interfaces shown in Listing 2. Normally, in addition to declaring that it "implements" an interface, a class would have to actually implement for all of the methods the interface declares. For simplicity, I've chosen not to declare any methods within any of the interfaces used in this example. That way, I can demonstrate the effect that interfaces have on assignments and casting without bogging the example classes down with excessive detail.
Reference Variables Mammal mammalVar; As I indicated previously, when I refer to an object's class, I am specifically referring to the name of the class used in the expression that created the object. According to the first part of Tenet 6 - Option A, a variable is always capable of holding a reference to an object whose class matches the variable's type: mammalVar = new Mammal(); The remaining part of Option A indicates that a variable can also hold a reference to any object whose class is a subtype of the variable's type. Therefore, since Dog and Whale are both subtypes of Mammal, the following assignments will also succeed:
mammalVar = new Dog(); Since Mammal is a class type, Option B does not apply. Using the words "is a", as we did earlier, is often a more intuitive way to determine if the variable is capable of holding a reference to a particular object. First, state the class of the object, then the words "is a", and finally, the type of the variable. The previous three assignments would be stated as:
A Mammal is a Mammal As long as you know that a whale really is a mammal, then each of the statements makes sense, meaning the assignment would succeed. If the class of the object was Animal, the false statement: An Animal is a Mammal would make it obvious (since not all animals are mammals) that the assignment would not be permitted. Let's move on to an example in which the type of the variable is an interface type: WaterDweller waterDwellerVar; This time, the pertinent part of Tenet 6 is Option B, which, applied to this particular case, indicates that the variable is capable of holding a reference to any object whose class implements the interface WaterDweller or any subtype of the interface WaterDweller. Since, as shown in Figure 2, FreshWaterDweller and SaltWaterDweller are both subtypes of WaterDweller the following assignments would succeed:
waterDwellerVar = new Fish(); What may not be intuitive is that the following assignment would also succeed: waterDwellerVar = new Salmon(); The Salmon class "inherits" the implementation of the WaterDweller interface from the Fish class.
Casting int intVar = 10; long longVar = intVar; The reason that this works is that the compiler can determine that there's plenty of room to store the smaller value (a 32-bit int) into the larger value (a 64-bit long) without any chance of information being lost. Therefore, prior to making the assignment, the compiler automatically converts the int value to a long value. In the opposite case, when a long value is being stored into an int variable, the compiler cannot guarantee that the value will fit. Therefore, the compiler forces you to include a cast operator which indicates that you are aware that the operation might cause some information to be lost, but want to do it anyway. The cast operator is the name of the type, that the value is to be converted to, enclosed within parenthesis: intVar = (int) longVar; Casting works slightly differently for variables of a reference type since, as Tenets 2 and 4 assert, neither the type of the variable nor the class of the object is ever changed. Let's look at another example: Salmon salmonVar = new Salmon(); Fish fishVar = salmonVar; In the first line, a variable named "salmonVar" of type Salmon is declared, a new object of class Salmon is created, and a reference to the newly created object is stored into "salmonVar". In the second line, a copy of the reference stored in the variable "salmonVar" is stored in the variable "fishVar." This assignment is permitted since the type of the variable "salmonVar" (Salmon) is a subtype of type of the variable "fishVar" (Fish). Note that the validity of the assignment has nothing to do with the class of the object, only the types of the respective variables are relevant. Just as the compiler is able to determine that no information will be lost when an int value is stored into a long variable, the compiler knows that a subtype will always be able to respond to all of the messages that can be sent to any of its supertypes. As before, in the opposite case, when a supertype is being assigned to a subtype, the compiler cannot determine that the operation will always succeed, so it requires the programmer to confirm his intention by including a cast. Thus, to assign a copy of the reference contained in "fishVar" to a new variable of type Salmon, a cast to type Salmon is required:
Salmon newVar = (Salmon) fishVar;
Sending Messages salmonVar.jump(); causes the message "jump()" to be sent to the object that the variable "salmonVar" refers to. As Tenet 7 indicates, it is the type of a variable, which holds a reference to an object, that determines which messages can be sent, via that variable, to the object. The implication of Tenet #7 is that an attempt to send the "jump()" message using the reference stored in the variable fishVar would fail. Keep in mind that the problem isn't on the object's end. Tenet 4 still applies. The object's class is still Salmon, and any object of class Salmon can respond appropriately to the message "jump()". The problem is that the "fishVar" variable's type is Fish and there isn't any method named "jump" defined in the Fish class or in any of its superclasses. Only variables of type Salmon (or if it had any, Salmon's subclasses) can be used to send the "jump" message to the object. Finally, as Tenet 8 indicates, it is the class of the object, which receives a message, that determines what happens in response to that message. It is very common for a subclass to "override" a method implemented in one of its superclasses. For example, the implementation of the movement method in the Mammal class returns the String "quadraped" since most mammals walk on four legs. The Whale class overrides the movement method so that it returns the more appropriate String "swim". The Whale object will always return "swim" in response to a movement message regardless of the type of the variable from which the message was sent.
The Test Reader Feedback: Page 1 of 1
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||