Previous Page TOC Next Page



- 5 -
Working with Objects


We'll start today's lesson with an obvious statement: because Java is an object-oriented language, you're going to be dealing with a lot of objects. You'll create them, modify them, move them around, change their variables, call their methods, combine them with other objects—and, of course, develop classes and use your own objects in the mix.

Today, therefore, you'll learn all about the Java object in its natural habitat. Today's topics include


Creating New Objects


When you write a VJ++ program, you define a set of classes. As you learned on Day 3, classes are templates for objects; for the most part, you merely use the class to create instances and then work with those instances. In this section, therefore, you'll learn how to create a new object from any given class.

Remember strings from yesterday? You learned that using a string literal—a series of characters enclosed in double-quotes—creates a new instance of the class String with the value of that string.

The String class is unusual in that respect—although it's a class, there's an easy way to create instances of that class using a literal. The other classes don't have that shortcut; to create instances of other classes you have to create them by using the new operator.



What about the literals for numbers and characters? Don't they create objects, too? Actually, they don't. Even though the primitive data types for numbers and characters create numbers and characters, for reasons of efficiency, they aren't actually objects. If you need to treat them like objects, you can put object-wrappers around them. (You'll learn how to do this later.)


Using new


To create a new object, you use new with the name of the class you want to create an instance of and then parentheses after that:




String str = new String();



Random r = new Random();



Motorcycle m2 = new Motorcycle();



Motorcycle m3;



m3 = new Motorcycle();


Notice how m2 and m3 are both instances of the class Motorcycle.

The parentheses are important; don't leave them off. The parentheses can be empty, in which case the most simple, basic object is created; or the parentheses can contain arguments that determine the initial values of data members or other initial qualities of that object. The number and type of arguments you can use with new are defined by the class itself by using a special method called a constructor; you'll learn about how to create constructors in your own classes later in the week.



Some classes might not allow you to create instances without any arguments. This is dependent on whether or not there is a constructor that accepts no parameters. You will learn later on how to check a class to make sure you are performing a valid initialization of an object.

For example, take the Date class, which creates date objects. Listing 5.1 is a Java application that shows three different ways of creating a Date object using new. You can test this program yourself. Create a new Project Workspace named CreateDates; open a new text file; type in the code; save it as CreateDates; insert it into your application; and then build and execute it using JVIEW.

Listing 5.1. Colleen's Date program.




 1: import java.util.Date;



 2:



 3: class CreateDates



 4: {



 5:



 6:     public static void main(String args[])



 7:     {



 8:         Date d1, d2, d3;



 9:



10:        d1 = new Date();



11:        System.out.println("Date 1: " + d1);



12:



13:         d2 = new Date(70, 9, 16, 8, 30);



14:         System.out.println("Date 2: " + d2);



15:



16          d3 = new Date("June 5 1959 3:24 PM");



17:         System.out.println("Date 3: " + d3);



18:     }



19: }

The preceding application produces the following output.




Date 1: Tue Feb 13 09:36:56 PST 1996



Date 2: Wed Sep 16 08:30:00 PDT 1970



Date 3: Fri Jun 05 15:24:00 PST 1959

In the preceding example, three different dates are created by using different arguments to new. The first instance (line 8) uses new with no arguments, which creates a Date object for today's date, as the first line of the output shows.

The second Date object you create in this example has five integer arguments. The arguments represent a date: year, month, day, hours, and seconds. And, as the output shows, this creates a Date object for that particular date: Wednesday, September 16, 1970, at 8:30 AM.

The third version of Date takes one argument, a string, representing the date as a text string. When the Date object is created, that string is parsed, and a Date object with that date and time is created. (See the third line of output.) The date string can take many different formats; see the JDK documentation for the Date class (part of the java.util package) for information about what strings you can use.

What new Does


What does new do? When you use the new operator, several things happen: first, the new instance of the given class is created, and memory is allocated for it. In addition (and most importantly), when the new object is created, a special method defined in the given class is called. This special method is called a constructor.

Constructors are special methods for creating and initializing new instances of classes. Constructors initialize the new object and its variables, create any other objects the object needs, and generally perform any other operations the object needs to initialize itself.

Multiple constructor definitions in a class can each have a different number or type of argument; then, when you use new, you can specify different arguments in the argument list, and the right constructor for those arguments will be called. That's how each of those date objects returned the same date output even though they were supplied different input.

When you create your own classes, you can define as many constructors as you need to implement that class' behavior. This is an example of function overloading. You'll learn how to create constructors on Day 7.

A Note on Memory Management


Memory management in Java is dynamic and automatic. When you create a new object in Java, Java automatically allocates the right amount of memory for that object in the heap. You don't have to allocate any memory for any objects explicitly; Java does it for you.

What happens when you're finished with that object? How do you de-allocate the memory that object uses? The answer is, again: memory management is automatic. Once you finish with an object, that object no longer has any live references to it. It won't be assigned to any variables you're still using or stored in any arrays. Java has a garbage collector that looks for unused objects and reclaims the memory that those objects are using. You don't have to do any explicit freeing of memory; you just have to make sure you're not still holding onto an object you want to get rid of. You'll learn more specific details about the Java garbage collector and how it works on Day 21.

Accessing and Setting Class Variables and Data Members


Now you have your very own object, and that object might have class variables or data members defined in it. How do you work with those variables? Easy! Class variables and data members behave in exactly the same ways as the local variables you learned about yesterday; you just refer to them in a slightly different way than you do regular variables in your code.

Getting Values


To get to the value of a data member, you use dot notation.

With dot notation, an data member or class variable name has two parts: the object on the left side of the dot and the variable on the right side of the dot.

For example, if you have an object assigned to the variable myObject, and that object has a variable called m_var, you refer to that variable's value like this:




myObject.m_var;

This form for accessing variables is an expression (it returns a value), and both sides of the dot are also expressions. This means that you can nest data member access. If that m_var data member itself holds an object, and that object has its own data member called m_bState, you can refer to it like this:




myObject.m_var.m_bState;

Dot expressions are evaluated left to right, so you start with myObject's variable m_var, which points to another object with the variable m_bState. You end up with the value of that state variable.



If you refer back to Table 4.7 (in yesterday's lesson) you'll also see that dot expressions are evaluated at the highest level of operator precedence.


Changing Values


Assigning a value to that variable is equally easy—just tack an assignment operator on the right side of the expression:




myObject.m_var.m_bState = true;

Listing 5.2 is an example of a program that tests and modifies the data members in a Point object. Point is part of the java.awt package and refers to a coordinate point with an x and a y value. The following is another Java application you can experiment with and test using JVIEW.

Listing 5.2. The TestPoint class.




 1: import java.awt.Point;



 2:



 3: class TestPoint



 4: {



 5:



 6:     public static void main(String args[])



 7:     {



 8:         Point pntPoint = new Point(10,10);



 9:



10:         System.out.println("X is " + pntPoint.x);



11:         System.out.println("Y is " + pntPoint.y);



12:



13:         System.out.println("Setting X to 5.");



14:         pntPoint.x = 5;



15:         System.out.println("Setting Y to 15.");



16:         pntPoint.y = 15;



17:



18:         System.out.println("X is " + pntPoint.x);



19:         System.out.println("Y is " + pntPoint.y);



20:



21:     }



22: }

The preceding application produces the following output.




X is 10



Y is 10



Setting X to 5.



Setting Y to 15.



X is 5



Y is 15

In this example, you first create an instance of Point where X and Y are both 10. (See line 8.) Lines 10 and 11 print out those individual values, and you can see dot notation at work there. Lines 13 through 16 change the values of those variables to 5 and 15, respectively. Finally, lines 18 and 19 print out the values of X and Y again to show how they've changed.

Class Variables


Class variables, as you learned before, are variables that are defined and stored in the class itself. Their values, therefore, apply to the class and to all its instances.

With data members, each new instance of the class gets a new copy of the data members that the class defines. Each instance can then change the values of its data members without affecting any other object's data members. With class variables, there is only one copy of that variable. Every instance of the class has access to that variable, but there is only one value. Changing the value of that variable changes it for all the instances of that class.

You define class variables by including the static keyword before the variable itself. You'll learn more about this on Day 6, but, for now, here is an example. Take the following partial class definition:




class FamilyMember



{



    static String c_sSurname = "Johnson";



    String m_sName;



    int m_iAge;



    ...



}

Instances of the class FamilyMember each have their own values for m_sName and m_iAge. But the class variable c_sSurname has only one value for all family members. Change c_sSurname, and all the instances of FamilyMember are affected.

To access class variables, you use the same dot notation as you do with data members. To get or change the value of the class variable, you can use either the instance or the name of the class on the left side of the dot. Both the lines of output in this example print the same value:




FamilyMember dad = new FamilyMember()



System.out.println("Family's surname is: " + dad.surname);



System.out.println("Family's surname is: " + FamilyMember.surname);

Because you can use an instance to change the value of a class variable, it's easy to become confused about class variables and where their values are coming from. (Remember, the value of a class variable affects all the instances.) For this reason, it's a good idea to use the name of the class when you refer to a class variable—it makes your code easier to read and strange results easier to debug.



If you think back to yesterday when we talked about variables and how you name them, you will recall that we suggested a rather simple convention: sVar for Strings, iVar for int, and so on and so forth. Today, if you look at the code examples, you probably will notice that we have added two new prefixes to the code examples. These are m_ and c_. These two new prefixes are used for data members (m_) and class variables (c_). By using these two prefixes along with the variable type prefixes (from yesterday), it should be rather easy to look at a variable and be able to tell a) what data type the variable is, and b) whether the variable is a data member, class variable, or local variable.


Calling Methods


Calling a method in objects is similar to referring to its data members: method calls also use dot notation. The object whose method you're calling is on the left side of the dot; the name of the method and its arguments is on the right side of the dot:




myObject.methodOne(arg1, arg2, arg3);

Note that all methods must have parentheses after them, even if that method takes no arguments:




myObject.methodNoArgs();

If the method you've called results in an object that itself has methods, you can nest methods as you would variables:



It is important to be careful when nesting methods and variables. Too many levels of nesting make for very complicated and hard-to-maintain code.





myObject.getClass().getName();

You can combine nested method calls and data member references as well:




myObject.m_var.methodTwo(arg1, arg2);

System.out.println(), the method you've been using all through the book this far, is a great example of nesting variables and methods. The System class (part of the java.lang package) describes system-specific behavior. System.out is a class variable that contains an instance of the class PrintStream that points to the standard output of the system. PrintStream instances have a println() method that prints a string to that output stream.

Listing 5.3 shows an example of calling some methods defined in the String class. Strings include methods for string tests and modification, similar to what you would expect in a string library in other languages. The following is another Java application you can experiment with and test using JVIEW.

Listing 5.3. Several uses of string methods.




 1: class TestString



 2: {



 3:



 4:     public static void main(String args[])



 5:     {



 6:         String sStr = "Now is the winter of our discontent";



 7:



 8:         System.out.println("The string is: " + sStr);



 9:         System.out.println("Length of this string: "



10:                 + sStr.length());



11:         System.out.println("The character at position 5: "



12:                 + sStr.charAt(5));



13:         System.out.println("The substring from 11 to 17: "



14:                 + sStr.substring(11, 17));



15:         System.out.println("The index of the character d: "



16:                 + sStr.indexOf('d'));



17:         System.out.print("The index of the beginning of the ");



18:         System.out.println("substring \"winter\":"



19:                 + sStr.indexOf("winter"));



20:         System.out.println("The string in upper case: "



21:                 + sStr.toUpperCase());



22:     }



23: }

The preceding application produces the following output.




The string is: Now is the winter of our discontent



Length of this string: 35



The character at position 5: s



The substring from positions 11 to 17: winter



The index of the character d: 25



The index of the beginning of the substring "winter": 11



The string in upper case: NOW IS THE WINTER OF OUR DISCONTENT

In line 6, you create a new instance of String by using a string literal. It's easier than using new and then putting the characters in individually. The remainder of the program simply calls different string methods to do different operations on that string:


Class Methods


Class methods, like class variables, apply to the class as a whole and not to its instances. Class methods are commonly used for general utility methods that might not operate directly on an instance of that class, but fit with that class conceptually. For example, the String class contains a class method called valueOf(), which can take one of many different types of arguments, such as integers, Booleans, other objects, and so on. The valueOf() method then returns a new instance of String containing the string value of the argument it was given. This method doesn't operate directly on an existing instance of String, but getting a string from another object or data type is definitely a String-like operation, and it makes sense to define it in the String class.

Class methods can also be useful for gathering general methods together in one place (the class). For example, the Math class, defined in the java.lang package, contains a large set of mathematical operations as class methods—there are no instances of the class Math, but you can still use its methods with numeric or Boolean arguments.

To call a class method, use dot notation as you do with instance methods. As with class variables, you can use either an instance of the class or the class itself on the left site of the dot. However, for the same reasons noted in the discussion on class variables, using the name of the class for class variables makes your code easier to read. The last two lines in this example produce the same result:




String s1, s2;



s1 = "dummy";



s2 = s1.valueOf(5);



s2 = String.valueOf(5);

References to Objects


As you work with objects, one important thing going on behind the scenes is the use of references to those objects. When you assign objects to variables, or pass objects as arguments to methods, you are passing references to those objects, not the objects themselves or copies of those objects.

An example should make this clearer. Examine the following snippet of code:




import java.awt.Point;



class ReferencesTest



{



    public static void main (String args[])



    {



        Point pnt1, pnt2;



        pnt1 = new Point(100, 100);



        pnt2 = pnt1;



        pnt1.x = 200;



        pnt1.y = 200;



        System.out.println("Point1: " + pnt1.x + ", " + pnt1.y);



        System.out.println("Point2: " + pnt2.x + ", " + pnt2.y);



    }



}

In this program, you declare two variables of type Point, and assign a new Point object to pnt1. Then you assign the value of pnt1 to pnt2.

Now, here's the challenge. After changing pnt1's x and y data members, what will pnt2 look like?

Here's the output of that program:




Point1: 200, 200



Point2: 200, 200

As you can see, pnt2 was also changed. When you assign the value of pnt1 to pnt2, you actually create a reference from pnt2 to the same object that pnt1 refers. Change the object that pnt2 refers to, and you also change the object that pnt1 points to, because both are references to the same object.

The fact that VJ++ uses references becomes particularly important when you pass arguments to methods. You'll learn more about this later on today, but keep these references in mind.



There are no explicit pointers or pointer arithmetic in Java—just references. However, with these references, and with Java arrays, you have most of the capabilities that you have with pointers, without the confusion and lurking bugs that explicit pointers can create.


Casting and Converting Objects and Primitive Types


Sometimes in your Java programs you might have a value stored somewhere that is not the data type that you want. Maybe it's an instance of the wrong class, or perhaps it's a float and you want it to be an int. To convert the value of one type to another, you use a mechanism called casting.

Casting is a mechanism of converting the value of an object or primitive data type into another object or primitive data type. The result of a cast is a new reference or value. This is also commonly referred to as typecasting.



Casting doesn't affect the original object or value.

Although the concept of casting is a simple one, in Java, the rules for what types can be converted to what other types are complicated by the fact that Java has both primitive types (int, float, boolean), and object types (String, Point, Window, and so on). There are three forms of casts and conversions to talk about in this section:


Casting Primitive Types


Casting between primitive types enables you to "convert" the value of one type to another primitive type—for example, to assign a number of one type to a variable of another type. Casting between primitive types most commonly occurs with the numeric types.



Boolean values cannot be cast to any other primitive type.

Often, if the type you are casting to is "larger" than the type of the value you're converting, you might not have to use an explicit cast. You can often automatically treat a byte or a character as an int, for example, or an int as a long, an int as a float, or anything as a double automatically. In most cases, because the larger type provides more precision than the smaller, no loss of information occurs when the value is cast. The exception is casting integers to floating-point values; casting an int or a long to a float, or a long to a double might cause some loss of precision.

To convert a large value to smaller type, you must use an explicit cast, because converting that value might result in a loss of precision. Explicit casts look like this:




(typename) value

In this form, typename is the name of the type you're converting to (for example: short, int, float, boolean), and value is the expression that you want to convert. The example below divides the values of x by the value of y and casts the result to an iTemp that is declared as an int:




int iTemp = (int) (x / y);

Note that because the precedence of casting is higher than that of arithmetic, you have to use parentheses so that the result of the division is what gets cast to iTemp.

Below is another example of simple primitive casting.




...



    long lVar = 4543;



    int ivar = (int) lVar;



...

In this example, the long value of 4543 is converted to an integer value of the same 4543. As you can see, casting primitives is fairly straightforward.

Casting Objects


Instances of classes can also be cast to instances of other classes, with one restriction: the class of the object you're casting and the class you're casting it to must be related by inheritance; that is, you can cast an object only to an instance of its class's sub—or superclass—not to any random class.

Analogous to converting a primitive value to a larger type, some objects might not need to be cast explicitly. In particular, because subclasses contain all the information in the superclass, you can use an instance of a subclass anywhere a superclass is expected. Suppose you have a method that takes two arguments: one of type Object, and one of type Number. You don't have to pass instances of those particular classes to that method. For the Object argument, you can pass any subclass of Object (any object, in other words), and for the Number argument you can pass in any instance of any subclass of Number (Integer, boolean, Float, and so on).

Casting an object to an instance of one of that object's superclasses loses the information the original subclass provided and requires a specific cast. To cast an object to another class, you use the same casting operation that you used for base types:




(classname) object

In this case, classname is the name of the class you want to cast the object to, and object is a reference to the object you're casting (the original). Note that casting creates a reference to the old object of the type classname; the old object still continues to exist as it did before.

Here's an (fictitious) example of a cast of an instance of the class GreenApple to an instance of the class Apple (where GreenApple is theoretically a subclass of Apple):




GreenApple a;



Apple a2;



a = new GreenApple();



a2 = (Apple) a;

In addition to casting objects to classes, you can also cast objects to interfaces—but only if that object's class or one of its superclasses actually implements that interface. Casting an object to an interface then enables you to call one of that interface's methods even if that object's class does not directly implement that interface. You'll learn more about interfaces in Week 3.

Converting Primitive Types to Objects and Vice Versa


Now you know how to cast a primitive type to another primitive type and how to cast between classes. How can you cast one to the other?

You can't! Primitive types and objects are very different things in Java and you can't automatically cast or convert between the two. However, the java.lang package includes several special classes that correspond to each primitive data type: Integer for ints, Float for floats, Boolean for booleans, and so on.

Using class methods defined in these classes, you can create an object-equivalent for all the primitive types using new. The following line of code creates an instance of the Integer class with the value 35:




Integer intTemp = new Integer(35);


Notice that the new variable prefix int is created here. This is used so you can instantly tell that intTemp is an object of data type integer.

Now that you have a primitive-type object (intTemp), you can treat it exactly as any other object variable: For example, you can call any Java function that requires a parameter of type object. Then, when you want the primitive values back again, there are methods for that as well—for example, the intValue() method extracts an int primitive value from an Integer object:




int iInt = intTemp.intValue();  // returns 35

See the VJ++ Books Online for detailed information on these special classes and for specifics on the methods for converting primitives to and from objects.

Odds and Ends


This section is a catchall for other information about working with objects, in particular:


Comparing Objects


Yesterday, you learned about operators for comparing values: equals, not equals, less than, and so on. Most of these operators work only on primitive types, not on objects. For the most part, the operators that you learned about yesterday do not in any way work on objects.

The exception to this rule is with the operators for equality: == (equal) and != (not equal). These operators, when used with objects, test whether the two operands (objects) refer to exactly the same object. Here is an example:




...



  Apple a = new Apple();



  Fruit b;



  b = a;



  if (a == b)



  {



     //Code executed when equality is true goes here



  }

The preceding example shows two objects, a and b, which both reference the same object created on the first line. In the preceding case, the line starting with //Code executed (replaced by actual VJ++ statements) would be executed because a does equal the same object as b. Don't worry about the if statement in this example; you will get to it tomorrow.

What should you do if you want to be able to compare instances of your class and have meaningful results? You have to implement special methods in your class, and you have to call those methods using those method names.



Java does not have the concept of operator overloading—that is, the capability of defining the behavior of the built-in operators by defining methods in your own classes. The built-in operators remain defined only for numbers. Don't confuse the concept of operator overload with function overloading: Java supports the latter, not the former.

A good example of this is the String class. It is possible to have two strings, two independent objects in memory with the same values—that is, the same characters in the same order. According to the == operator, however, those two String objects will not be equal, because, although their contents are the same, they are not the same object.

The String class, therefore, defines a method called equals() that tests each character in the string and returns true if the two strings have the same values. The following is another Java application you can experiment with and test using JVIEW. Listing 5.4 illustrates this.

Listing 5.4. A test of string equality.




 1: class EqualsTest



 2: {



 3:     public static void main(String args[])



 4:    {



 5:         String sStr1, sStr2;



 6:         sStr1 = "she sells sea shells by the sea shore.";



 7:         sStr2 = sStr1;



 8:



 9:         System.out.println("String1: " + sStr1);



10:        System.out.println("String2: " + sStr2);



11:        System.out.println("Same object? " + (sStr1 == sStr2));



12:



13:         sStr2 = new String(sStr1);



14:



15:         System.out.println("String1: " + sStr1);



16:         System.out.println("String2: " + sStr2);



17:         System.out.println("Same object? " + (sStr1 == sStr2));



18:         System.out.println("Same value? " + sStr1.equals(sStr2));



19:     }



20: }

The preceding application produces the following output.




String1: she sells sea shells by the sea shore.



String2: she sells sea shells by the sea shore.



Same object? true



String1: she sells sea shells by the sea shore.



String2: she sells sea shells by the sea shore.



Same object? false



Same value? true

The first part of this program (lines 5 through 7) declares two variables, sStr1 and sStr2, assigns the literal she sells sea shells by the sea shore. to sStr1, and then assigns that value to sStr2. As you know from object references, now sStr1 and sStr2 point to the same object, and the test at line 11 proves that.

In the second part, you create a new string object with the value of sStr1. Now you have two different string objects with the same value. Testing them to see whether they're the same object by using the == operator (line 17) returns the expected answer, as does testing them using the equals method (line 18) to compare their values.



Why can't you just use another literal when you change sStr2, rather than using new? String literals are optimized in Java—if you create a string using a literal, and then use another literal with the same characters, Java knows enough to give you the first String object back. Both strings are the same objects—to create two separate objects you have to go out of your way.


Determining the Class of an Object


Want to find out the class of an object? Here's the way to do it for an object assigned to the variable obj:




String sName = obj.getClass().getName();

What does this do? The getClass() method is defined in the Object class, and, as such, is available for all objects. The result of that method is a Class object (where Class is itself a class), which has a method called getName(). getName() returns a string representing the name of the class.

Another test that might be useful to you is the instanceof operator. instanceof has two operands: an object on the left and the name of a class on the right. The expression returns true or false based on whether the object is an instance of the named class or any of that class' subclasses:




"dummy" instanceof String // true



Point pntPt = new Point(10, 10);



pntPt instanceof String // false

The instanceof operator can also be used for interfaces; if an object implements an interface, the instanceof operator with that interface name on the right side returns true. You'll learn all about interfaces in Week 3.

The Java Class Library


To finish up today, look at some of the components that make up the Java class libraries. Actually, you've had a bit of experience with these libraries during the past five days, so they shouldn't seem all that different.



There can be different class libraries available to you—the VJ++ developer—than those available to other developers and the user. The standard Java class libraries included with the JDK are the same ones included with VJ++, other development environments, and on a user's computer. However, there are specific class libraries that are currently only available with VJ++.

The Java class library provides the set of classes that are guaranteed to be supported in any commercial Java environment, for example, in Microsoft Internet Explorer 3.0 or in Netscape 2.0x. Those classes are in the Java package and include all the classes you've seen so far in this book, plus a whole lot more classes you'll learn about later on in this book. (And even more that we can't teach you about in 21 days.)

The VJ++ comes with full online documentation (Books Online) for all of the Java class libraries, which includes descriptions of each class' data members, methods, constructors, interfaces, and so on. A shorter summary of the Java API is in Appendix C as well. Exploring the Java class library and its methods and data members is a great way to figure out what Java can and cannot do, as well as a starting point for your own development.

Here are the class packages that are part of the Java class library:

Although the additional classes available to you as a VJ++ developer are incredibly useful, be careful. They are not part of the standard Java library and there is no guarantee that they will be available to other people across the Internet trying to run your Java program. You'll need to do a little extra planning and programming to help ensure that your Microsoft extensions to the Java language are executed properly on the user's computer. This is particularly important for applets, because applets are expected to be able to run on any platform, using any Java-capable Internet browser. Only classes inside the Java package are guaranteed to be available on all browsers and Java environments.

If you want the highest level of usability without the extra work, a good rule of thumb would be: for Internet applets, stick to the basic Java classes. For intranet applications, use any and all classes that you want; it's relatively easy to distribute across an intranet.

Summary


Objects, objects everywhere. Today, you learned all about how to deal with objects: how to create them, how to find out and change the values of their variables, and how to call their methods. You also learned how to copy and compare them, and how to convert them into other objects. Finally, you learned a bit about the Java class libraries—which give you a whole slew of classes to play with in your own programs.

You now have the fundamentals of how to deal with the most simple things in the Java language. All you have left are arrays, conditionals, and loops, which you'll learn about tomorrow. Then you'll learn how to define and use classes in Java applications on Day 7, and launch directly into applets next week.

Remember, with just about everything you do in your VJ++ programs, no matter how complex they become, or how much the language evolves, you'll always be writing in objects.

Q&A


Q: I'm confused about the differences between objects and the primitive data types, such as int and boolean.

A: The primitive types in the language (byte, short, int, long, float, double, boolean and char) represent the smallest things in the language. They are not objects, but they can be assigned to variables and passed in and out of methods like objects. However, most of the operations that work exclusively on objects will not work on them.

Objects are instances of classes and, as such, are much more complex data types than simple numbers and characters. Often, objects contain numbers and characters as data members or class variables.

Q: In the section on calling methods, you had examples of calling a method with a different number of arguments each time—and it gave a different kind of result. How is that possible?

A: That's called method overloading. Overloading enables the same function name to have different behaviors based on the arguments it's called with—and the number and type of arguments can vary. When you define methods in your own classes, you define separate method signatures with different sets of arguments and different definitions. When a method is called, Java figures out which definition to execute based on the number and type of arguments with which you called it.

You'll learn all about this on Day 6.

Q: No operator overloading in Java? Why not? I thought Java was based on C++, and C++ has operator overloading.

A: Java was indeed based on C++, but it was also designed to be simple, so many of C++'s features have been removed. The argument against operator overloading is that, because the operator can be defined to mean anything, it makes it very difficult to figure out what any given operator is doing at any one time. This can result in entirely unreadable code. When you use a method, you know it can mean many things to many classes, but when you use an operator you would like to know that it always means the same thing. Given the potential for abuse, the designers of Java felt it was one of the C++ features that was best left out.

Previous Page Page Top TOC Next Page