Java Help, Java Tutorials, Java Programming, Java Tricks
lesson four
Working with Objects
CONTENTS
Creating New Objects
Using new
What new Does
A Note on Memory Management
Accessing and Setting Class and Instance Variables
Getting Values
Changing Values
Class Variables
Calling Methods
Class Methods
References to Objects
Casting and Converting Objects and Primitive Types
Casting Primitive Types
Casting Objects
Converting Primitive Types to Objects and Vice Versa
Odds and Ends
Comparing Objects
Determining the Class of an Object
Class and Object Reflection (Java 1.1)
The Java Class Library
Summary
Q&A
Let's 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 instances of classes
Testing and modifying class and instance variables in your new instance
Calling methods in that object
Casting (converting) objects and other data types from one class to another
Other odds and ends about working with objects
An overview of the Java class libraries
Creating New Objects
When you write a Java program, you define a set of classes. As you learned on
Day 2, "Object-Oriented
Programming and Java," 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 those classes you
have to do so explicitly by using the new operator.
Note
What about the literals for numbers and characters? Don't they create
objects, too? Actually, they don't. The primitive data types for
numbers and characters create numbers and characters, but for
efficiency, they aren't actually objects. You can put object wrappers
around them if you need to treat them like objects (you'll learn how to
do this in "Casting and `Converting Objects and Primitive Types").
Using new
To create a new object, you use the new operator with the name of the class you
want to create an instance
of, then parentheses after that. The following examples create new instances of
the classes String,
Random, and Motorcycle, and store those new instances in variables of the
appropriate types:
String str = new String();
Random r = new Random();
Motorcycle m2 = new Motorcycle();
The parentheses are important; don't leave them off. The parentheses can be
empty (as in these examples),
in which case the most simple, basic object is created; or the parentheses can
contain arguments that
determine the initial values of instance variables or other initial qualities of
that object:
Date dt = new Date(90, 4, 1, 4, 30);
Point pt = new Point(0,0);
The number and type of arguments you can use inside the parentheses with new are
defined by the class
itself using a special method called a constructor (you'll learn more about
constructors later today). If you
try and create a new instance of a class with the wrong number or type of
arguments (or if you give it no
arguments and it needs some), then you'll get an error when you try to compile
your Java program.
Here's an example of creating several different types of objects using different
numbers and types of
arguments. The Date class, part of the java.util package, creates objects that
represent the current
date. Listing 4.1 is a Java program that shows three different ways of creating
a Date object using new.
Listing 4.1. Laura's Date program.
1: import java.util.Date;
2:
3: class CreateDates {
4:
5: public static void main(String args[]) {
6: Date d1, d2, d3;
7:
8: d1 = new Date();
9: System.out.println("Date 1: " + d1);
10:
11: d2 = new Date(71, 7, 1, 7, 30);
12: System.out.println("Date 2: " + d2);
13:
14: d3 = new Date("April 3 1993 3:24 PM");
15: System.out.println("Date 3: " + d3);
16: }
17: }
Date 1: Tue Feb 13 09:36:56 PST 1996
Date 2: Sun Aug 01 07:30:00 PDT 1971
Date 3: Sat Apr 03 15:24:00 PST 1993
Analysis
In this example, three different date objects are created using different
arguments to the class listed after new. The first instance (line 8) uses
new Date() with no arguments, which creates a Date object for
today's date (the first line of the output shows a sample; your output
will, of course, read the current date and time for you).
The second Date object you create in this example has five integer arguments.
The arguments represent a
date: year, month, day, hours, and minutes. And, as the output shows, this
creates a Date object for that
particular date: Sunday, August 1, 1971, at 7:30 a.m.
Note
Java numbers months starting from 0. So although you might expect
the seventh month to be July, month 7 in Java is indeed August.
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
API documentation for the
Date class (part of the java.util package) for information about what strings
you can use.
What new Does
When you use the new operator, the new instance of the given class is created,
and memory is allocated
for it. In addition (and most importantly), a special method defined in the
given class is called to initialize
the object and set up any initial values it needs. This special method is called
a constructor. Constructors
are special methods, defined in classes, that create and initialize new
instances of classes.
New Term
Constructors are special methods that initialize a new object, set its
variables, create any other objects that 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 arguments-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 different versions of
new that you used in the
CreateDates class can create different Date objects.
When you create your own classes, you can define as many constructors as you
need to implement that
class's behavior. You'll learn how to create constructors on Day 7, "More About
Methods."
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, again, is that memory management is automatic. Once you're
done with an object, you
reassign all the variables that might hold that object and remove it from any
arrays, thereby making the
object unusable. 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, "Under the Hood."
New Term
A garbage collector is a special thing built into the Java environment
that looks for unused objects. If it finds any, it automatically removes
those objects and frees the memory those objects were using.
Accessing and Setting Class and Instance Variables
Now you have your very own object, and that object may have class or instance
variables defined in it.
How do you work with those variables? Easy! Class and instance variables behave
in exactly the same
ways as the local variables you learned about yesterday; you just refer to them
slightly differently than you
do regular variables in your code.
Getting Values
To get to the value of an instance variable, you use an expression in what's
called dot notation. With dot
notation, the reference to an instance or class variable has two parts: the
object on the left side of the dot
and the variable on the right side of the dot.
New Term
Dot notation is an expression used to get at instance variables and
methods inside a given object.
For example, if you have an object assigned to the variable myObject, and that
object has a variable
called var, you refer to that variable's value like this:
myObject.var;
This form for accessing variables is an expression (it returns a value), and
both sides of the dot can also be
expressions. This means that you can nest instance variable access. If that var
instance variable itself
holds an object and that object has its own instance variable called state, you
could refer to it like this:
myObject.var.state;
Dot expressions are evaluated left to right, so you start with myObject's
variable var, which points to
another object with the variable state. You end up with the value of that state
variable after the entire
expression is done evaluating.
Changing Values
Assigning a value to that variable is equally easy-just tack an assignment
operator on the right side of the
expression:
myObject.var.state = true;
Listing 4.2 is an example of a program that tests and modifies the instance
variables 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.
Listing 4.2. The TestPoint Class.
1: import java.awt.Point;
2:
3: class TestPoint {
4: public static void main(String args[]) {
5: Point thePoint = new Point(10,10);
6:
7: System.out.println("X is " + thePoint.x);
8: System.out.println("Y is " + thePoint.y);
9:
10: System.out.println("Setting X to 5.");
11: thePoint.x = 5;
12: System.out.println("Setting Y to 15.");
13: thePoint.y = 15;
14:
15: System.out.println("X is " + thePoint.x);
16: System.out.println("Y is " + thePoint.y);
17:
18: }
19:}
X is 10
Y is 10
Setting X to 5.
Setting Y to 15.
X is 5
Y is 15
Analysis
In this example, you first create an instance of Point where X and Y
are both 10 (line 6). Lines 8 and 9 print out those individual values,
and you can see dot notation at work there. Lines 11 through 14
change the values of those variables to 5 and 15, respectively.
Finally, lines 16 and 17 print out the values of X and Y again to show
how they've changed.
Class Variables
Class variables, as you've already learned, are variables that are defined and
stored in the class itself. Their
values, therefore, apply to the class and to all its instances.
With instance variables, each new instance of the class gets a new copy of the
instance variables that class
defines. Each instance can then change the values of those instance variables
without affecting any other
instances. 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, "Creating Classes and Applications in Java." For example,
take the following partial
class definition:
class FamilyMember {
static String surname = "Johnson";
String name;
int age;
...
}
Instances of the class FamilyMember each have their own values for name and age.
But the class
variable surname has only one value for all family members. Change surname, and
all the instances of
FamilyMember are affected.
To access class variables, you use the same dot notation as you do with instance
variables. 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 of 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 that 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.
Calling Methods
Calling a method is similar to referring to an object's instance variables:
Method calls to objects also use
dot notation. The object itself whose method you're calling is on the left side
of the dot; the name of the
method and its arguments are on the right side of the dot:
myObject.methodOne(arg1, arg2, arg3);
Note that all calls to methods must have parentheses after them, even if that
method takes no arguments:
myObject.methodNoArgs();
If the method you've called returns an object that itself has methods, you can
nest methods as you would
variables. This next example calls the getName() method, which is defined in the
object returned by the
getClass() method, which was defined in myObject. Got it?
myObject.getClass().getName();
You can combine nested method calls and instance variable references as well (in
this case you're calling
the methodTwo() method, which is defined in the object stored by the var
instance variable, which in
turn is part of the myObject object):
myObject.var.methodTwo(arg1, arg2);
System.out.println(), the method you've been using through the book this far to
print out bits of
text, 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 4.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.
Listing 4.3. Several uses of String methods.
1: class TestString {
2:
3: public static void main(String args[]) {
4: String str = "Now is the winter of our discontent";
5:
6: System.out.println("The string is: " + str);
7: System.out.println("Length of this string: "
8: + str.length());
9: System.out.println("The character at position 5: "
10: + str.charAt(5));
11: System.out.println("The substring from 11 to 17: "
12: + str.substring(11, 17));
13: System.out.println("The index of the character d: "
14: + str.indexOf('d'));
15: System.out.print("The index of the beginning of the ");
16: System.out.println("substring \"winter\": "
17: + str.indexOf("winter"));
18: System.out.println("The string in upper case: "
19: + str.toUpperCase());
20: }
21: }
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
Analysis
In line 4, you create a new instance of String by using a string
literal (it's easier that way 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:
Line 6 prints the value of the string we created in line 4: "Now is the winter
of our
discontent".
l
Line 7 calls the length() l method in the new String object. This string has 35
characters.
Line 9 calls the charAt() method, which returns the character at the given
position in the string.
Note that string positions start at 0, so the character at position 5 is s.
l
Line 11 calls the substring() method, which takes two integers indicating a
range and returns
the substring at those starting and ending points. The substring() method can
also be called
with only one argument, which returns the substring from that position to the
end of the string.
l
Line 13 calls the indexOf() method, which returns the position of the first
instance of the given
character (here, 'd').
l
Line 15 shows a different use of the indexOf() method, which takes a string
argument and
returns the index of the beginning of that string.
l
l Finally, line 19 uses the toUpperCase() method to return a copy of the string
in all uppercase.
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 may 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 (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. For example, the class method Math.max()
takes two arguments
and returns the larger of the two. You don't need to create a new instance of
Math; just call the method
anywhere you need it, like this:
in biggerOne = Math.max(x, y);
To call a class method, you 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 methods makes
your code easier to read. The last two lines in this example produce the same
result (the string "5"):
String s, s2;
s = "foo";
s2 = s.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 Listing 4.4, which shows a simple
example of how
references work.
Listing 4.4. A references example.
1: import java.awt.Point;
2:
3: class ReferencesTest {
4: public static void main (String args[]) {
5: Point pt1, pt2;
6: pt1 = new Point(100, 100);
7: pt2 = pt1;
8:
9: pt1.x = 200;
10: pt1.y = 200;
11: System.out.println("Point1: " + pt1.x + ", " + pt1.y);
12: System.out.println("Point2: " + pt2.x + ", " + pt2.y);
13: }
14: }
Point1: 200, 200
Point2: 200, 200
Analysis
In the first part of this program, you declare two variables of type
Point (line 5), create a new Point object to pt1 (line 6), and
finally, assign the value of pt1 to pt2 (line 7).
Now, here's the challenge. After changing pt1's x and y instance variables in
lines 9 and 10, what will
pt2 look like?
As you can see, pt2's x and y instance variables were also changed, even though
you never explicitly
changed them. When you assign the value of pt1 to pt2, you actually create a
reference from pt2 to the
same object to which pt1 refers (see Figure 4.1). Change the object that pt2
refers to, and you also
change the object that pt1 points to, because both are references to the same
object.
Figure 4.1 : References to objects.
Note
If you actually do want pt1 and pt2 to point to separate objects, you
should use new Point() for both lines to create separate objects.
The fact that Java uses references becomes particularly important when you pass
arguments to methods.
You'll learn more about this later today, but keep these references in mind.
Technical Note
There are no explicit pointers or pointer arithmetic in Java as there are
in C-like languages-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 may have a value stored somewhere that is
the wrong type for what
you want to do with it. 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 casting.
Casting is a programming term
that means, effectively, converting a value or an object from one type to
another. The result of a cast is a
new value or object; casting does not change the original object or value.
New Time
Casting converts the value of an object or primitive type into another
type.
Although the concept of casting is a simple one, the rules for what types in
Java 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 between primitive types: int to float or float l to double
l Casting between object types: an instance of a class to an instance of another
class
l Converting primitive types to objects and then extracting primitive values
back out of those objects
Casting Primitive Types
Casting between primitive types allows 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 may 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 may cause some loss of precision.
To convert a large value to smaller type, you must use an explicit cast, because
converting that value may
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 an expression that results in the value you want to
convert. So, for example, in
this expression the value of x is divided by the value of y and the result is
cast to an int:
(int) (x / y);
Note that because the precedence of casting is higher than that of arithmetic,
you have to use parentheses
here; otherwise, the value of x would be cast first and then divided by y (which
might very well be a very
different result).
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 may not
need to be cast
explicitly. In particular, because subclasses contain all the same information
as their superclass, you can
use an instance of a subclass anywhere a superclass is expected. (Did you just
have to read that sentence
four times before you understood it? I had to rewrite it a whole lot of times
before it became even that
simple. Bear with me, its not that bad. Let's try an example.) 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); you don't have to explicitly
convert them first.
Casting downward in the class hierarchy is automatic, but casting upward is not.
Converting an instance of
a subclass to an instance of a superclass loses the information the original
subclass provided and requires
an explicit 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. 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 a (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 with more
information to define the
apple as green):
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 means
that you can call one of that interface's methods even if that object's class
does not actually 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. Note that the class names have an initial capital letter,
and the primitive types are
lowercase. Java treats these names very differently, so don't confuse them, or
your methods and variables
won't behave the way you expect.
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 intObject = new Integer(35);
Once you have actual objects, you can treat those values as objects. 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 theInt = intObject.intValue(); // returns 35
See the Java API documentation for these special classes for specifics on the
methods for converting
primitives to and from objects.
Note
In Java 1.0 there are special type classes for Boolean,
Character, Double, Float, Integer, and Long. Java 1.1
adds classes for Byte and Short, as well as a special wrapper class
for Void. The latter classes are used primarily for object reflection.
Odds and Ends
This section is a catchall for other information about working with objects,
particularly the following:
l Comparing objects
l Finding out the class of any given object
l Testing to see whether an object is an instance of a given class
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. If you try to
use other values as operands,
the Java compiler produces errors.
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 refer to
exactly the same object in
memory.
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.
Technical Note
Java does not have the concept of operator overloading-that is, the
ability to redefine the behavior of the built-in operators using methods
in your own classes. The built-in operators remain defined only for
numbers.
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. Listing 4.5
illustrates this.
Listing 4.5. A test of string equality.
1: class EqualsTest {
2: public static void main(String args[]) {
3: String str1, str2;
4: str1 = "she sells sea shells by the sea shore.";
5: str2 = str1;
6:
7: System.out.println("String1: " + str1);
8: System.out.println("String2: " + str2);
9: System.out.println("Same object? " + (str1 == str2));
10:
11: str2 = new String(str1);
12:
13: System.out.println("String1: " + str1);
14: System.out.println("String2: " + str2);
15: System.out.println("Same object? " + (str1 == str2));
16: System.out.println("Same value? " + str1.equals(str2));
17: }
18: }
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
Analysis
The first part of this program (lines 4 through 6) declares two
variables (str1 and str2) assigns the literal she sells sea
shells by the sea shore. to str1, and then assigns that
value to str2. As you learned earlier when we talked about object
references, now str1 and str2 point to the same object, and the
equality test at line 10 proves that.
In the second part, you create a new string object with the same value as str1
and assign str2 to that
new string object. Now you have two different string objects in str1 and str2,
both with the same
value. Testing them to see whether they're the same object by using the ==
operator (line 16) returns the
expected answer (false-they are not the same object in memory), as does testing
them using the
equals() method (line 17) (true-they have the same values).
Technical Note
Why can't you just use another literal when you change str2, 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 name = 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's
subclasses:
"foo" instanceof String // true
Point pt = new Point(10, 10);
pt 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.
Class and Object Reflection (Java 1.1)
Reflection, also known as introspection, is a somewhat lofty term to describe
the ability to "look inside" a
class or an object and get information about that object's variables and methods
as well as actually set and
get the values of those variables and to call methods. Object reflection is
useful for tools such as class
browsers or debuggers, where getting at the information of an object on-the-fly
allows you to explore what
that object can do, or for component-based programs such as Java Beans, where
the ability for one object
to query another object about what it can do (and then ask it to do something)
is useful to building larger
applications.
The classes that support reflection of Java classes and objects will be part of
the core Java 1.1 API (they
are not available in the 1.0.2 version of the JDK). A new package,
java.lang.reflect, will contain
new classes to support reflection, which include the following:
l Field, for managing and finding out information about class and instance
variables
l Method, for managing class and instance methods
Constructor, for managing the special methods for creating new instances of
classes (you'll
learn more about constructors on Day 7)
l
l Array, for managing arrays
Modifier, for decoding modifier information about classes, variables and methods
(more about
modifiers on Day 15, "Modifiers, Access Control, and Class Design")
l
In addition, there will be a number of new methods available in the Class class
to help tie together the
various reflection classes.
You can find out more about the new reflection classes and methods from
http://java.sun.com/products/JDK/1.1/designspecs/reflection/.
The Java Class Library
To finish up today, let's look at the Java class library. Actually, you've had
some experience with some of
the Java classes already, so they shouldn't seem that strange.
The Java class library provides the set of classes that are guaranteed to be
available in any commercial
Java environment (for example, in any Java development environment or in
browsers such as Netscape).
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 more you
may not learn about at all).
The Java Developer's Kit comes with documentation for all of the Java class
library, which includes
descriptions of each class's instance variables, methods, constructors,
interfaces, and so on. You can get to
this documentation (called the Java Application Programmer's Interface, or API)
via the Web at
http://java.sun.com:80/products/JDK/CurrentRelease/api/packages.html. A
shorter summary of the Java API is in appendix C as well. Exploring the Java
class library and its methods
and instance variables is a great way to figure out what Java can and cannot do,
as well as how it can
become a starting point for your own development.
Here are the class packages that are part of the Java class library:
java.lang-Classes that apply to the language itself, including the Object class,
the String
class, and the System class. It also contains the special classes for the
primitive types (Integer,
Character, Float, and so on). You'll get at least a glance at most of the
classes in this package
in this first week.
l
java.util-Utility classes, such as Date, as well as simple collection classes,
such as Vector
and Hashtable. You'll learn more about these classes in the Bonus Week.
l
java.io-Input and output classes for writing to and reading from streams (such
as standard input
and output) and for handling files. Day 19, "Streams and I/O," describes the
classes in this package.
l
java.net-Classes for networking support, including Socket and URL (a class to
represent
references to documents on the World Wide Web). You'll learn a little about
networking on Day 14,
"Windows, Networking, and Other Tidbits," and then on Day 26, "Client/Server
Networking in
Java."
l
java.awt-This is the Abstract Windowing Toolkit. It contains classes to
implement graphical
user interface features, including classes for Window, Menu, Button, Font,
CheckBox, and so
on. It also includes mechanisms for managing system events and for processing
images (in the
java.awt.Image package). You'll learn all about the awt in Week 2.
l
l java.applet-Classes to implement Java applets.
In addition to the Java classes, your development environment may also include
additional classes that
provide other utilities or functionality. Although these classes may be useful,
because they are not part of
the standard Java library, they may not be available to other people trying to
run your Java program unless
you explicitly include those classes with your program. This is particularly
important for applets, because
applets are expected to be able to run on any platform, using any Java-enabled
browser. Only classes
inside the java package are guaranteed to be available on all browsers and Java
environments.
Summary
Objects, objects everywhere. Today, you've 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 have
also learned how to copy and compare them and how to convert them into other
objects. Finally, you have
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 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 6, and launch directly into
applets next week. With just
about everything you do in your Java programs, you'll always come back to
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,
although in many
ways they can be handled like objects-they can be assigned to variables and
passed in and out of
methods. Most of the operations that work exclusively on objects, however, will
not work with
primitive types.
Objects are instances of classes and, as such, are usually much more complex
data types than
simple numbers and characters, often containing numbers and characters as
instance or class
variables.
Q: No pointers in Java? If you don't have pointers, how are you supposed to do
something like
linked lists, where you have a pointer from one nose to another so you can
traverse them?
A: Java doesn't have no pointers at all; it has no explicit pointers. Object
references are, effectively,
pointers. So to create something like a linked list, you would create a class
called Node, which
would have an instance variable also of type Node. Then to link together node
objects all you
need to do is assign a node object to the instance variable of the object just
before it in the list.
Because object references are pointers, linked lists set up this way will behave
as you would
expect them to.
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 means that the same method can
have different
behavior 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.