Java in a Nutshell, 5th Edition [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java in a Nutshell, 5th Edition [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


3.8. Important Methods of java.lang.Object


As
we've noted, all
classes extend, directly or indirectly,
java.lang.Object. This class defines several
important methods that you should consider overriding in every class
you write. Example 3-6 shows a class that overrides
these methods. The sections that follow the example document the
default implementation of each method and explain why you might want
to override it. You may also find it helpful to look up
Object in the reference section for an API
listing.

Some of the syntax in Example 3-6 may be unfamiliar
to you. The example uses two Java 5.0 features. First, it implements
a parameterized, or generic, version of the
Comparable interface. Second, the example uses the
@Override

annotation to emphasize (and have the compiler verify) that certain
methods override Object.
Parameterized types and annotations are covered in Chapter 4.


Example 3-6. A class that overrides important Object methods

// This class represents a circle with immutable position and radius.
public class Circle implements Comparable<Circle> {
// These fields hold the coordinates of the center and the radius.
// They are private for data encapsulation and final for immutability
private final int x, y, r;
// The basic constructor: initialize the fields to specified values
public Circle(int x, int y, int r) {
if (r < 0) throw new IllegalArgumentException("negative radius");
this.x = x; this.y = y; this.r = r;
}
// This is a "copy constructor"--a useful alternative to clone()
public Circle(Circle original) {
x = original.x; // Just copy the fields from the original
y = original.y;
r = original.r;
}
// Public accessor methods for the private fields.
// These are part of data encapsulation.
public int getX() { return x; }
public int getY() { return y; }
public int getR() { return r; }
// Return a string representation
@Override public String toString() {
return String.format("center=(%d,%d); radius=%d", x, y, r);
}
// Test for equality with another object
@Override public boolean equals(Object o) {
if (o == this) return true; // Identical references?
if (!(o instanceof Circle)) return false; // Correct type and non-null?
Circle that = (Circle) o; // Cast to our type
if (this.x == that.x && this.y == that.y && this.r == that.r)
return true; // If all fields match
else
return false; // If fields differ
}
// A hash code allows an object to be used in a hash table.
// Equal objects must have equal hash codes. Unequal objects are allowed
// to have equal hash codes as well, but we try to avoid that.
// We must override this method since we also override equals().
@Override public int hashCode() {
int result = 17; // This hash code algorithm from the book
result = 37*result + x; // _Effective Java_, by Joshua Bloch
result = 37*result + y;
result = 37*result + r;
return result;
}
// This method is defined by the Comparable interface.
// Compare this Circle to that Circle. Return a value < 0 if this < that.
// Return 0 if this == that. Return a value > 0 if this > that.
// Circles are ordered top to bottom, left to right, and then by radius
public int compareTo(Circle that) {
long result = that.y - this.y; // Smaller circles have bigger y values
if (result == 0) result = this.x - that.x; // If same compare l-to-r
if (result == 0) result = this.r - that.r; // If same compare radius
// We have to use a long value for subtraction because the differences
// between a large positive and large negative value could overflow
// an int. But we can't return the long, so return its sign as an int.
return Long.signum(result); // new in Java 5.0
}
}


3.8.1. toString()


The purpose of the toString(
)

method is to return a textual representation of an object. The method
is invoked automatically on objects during string concatenation and
by methods such as System.out.println( ). Giving
objects a textual representation can be quite helpful for debugging
or logging output, and a well-crafted toString()
method can even help with tasks such as report generation.

The version of toString() inherited from
Object returns a string that includes the name of
the class of the object as well as a hexadecimal representation of
the hashCode() value of the object (discussed
later in this chapter). This default implementation provides basic
type and identity information for an object but is not usually very
useful. The toString( ) method in Example 3-6 instead returns a human-readable string that
includes the value of each of the fields of the
Circle class.


3.8.2. equals( )


The
= = operator tests two references to see
if they refer to the same object. If you want to test whether two
distinct objects are equal to one another, you must use the
equals() method instead. Any class can define its
own notion of equality by overriding equals(). The
Object.equals( ) method simply uses the
== operator: this default method considers two
objects equal only if they are actually the very same object.

The equals( ) method in Example 3-6 considers two distinct
Circle objects to be equal if their fields are all
equal. Note that it first does a quick identity test with =
=
as an optimization and then checks the type of the other
object with
instanceof: a Circle can be
equal only to another Circle, and it is not acceptable for an
equals() method to throw a
ClassCastException. Note that the
instanceof test also rules out
null arguments: instanceof
always evaluates to false if its left-hand operand
is null.


3.8.3. hashCode( )


Whenever you override equals( ), you must also
override hashCode( )
. This
method returns an integer for use by hash table data structures. It
is critical that two objects have the same hash code if they are
equal according to the equals() method. It is
important (for efficient operation of hash tables) but not required
that unequal objects have unequal hash codes, or at least that
unequal objects are unlikely to share a hash code. This second
criterion can lead to hashCode() methods that
involve mildly tricky arithmetic or bit-manipulation.

The Object.hashCode() method works with the
Object.equals( ) method and returns a hash code
based on object identity rather than object equality. (If you ever
need an identity-based hash code, you can access the functionality of
Object.hashCode() through the static method
System.identityHashCode( ).) When you override
equals( ), you must always override
hashCode() to guarantee that equal objects have
equal hash codes. Since the equals( ) method in
Example 3-6 bases object equality on the values of
the three fields, the hashCode( ) method computes
its hash code based on these three fields as well. It is clear from
the code that if two Circle objects have the same
field values, they will have the same hash code.

Note that the hashCode( ) method in Example 3-6 does not simply add the three fields and
return their sum. Such an implementation would be legal but not
efficient because two circles with the same radius but whose X and Y
coordinates were reversed would then have the same hash code. The
repeated multiplication and addition steps "spread
out" the range of hash codes and dramatically reduce
the likelihood that two unequal Circle objects
have the same code.

Effective Java Programming
Guide by Joshua Bloch (Addison Wesley)
includes a helpful recipe for constructing efficient
hashCode() methods like this one.


3.8.4. Comparable.compareTo( )


Example 3-6 includes a compareTo(
)



method. This method is defined by the
java.lang.Comparable interface rather than by
Object. (It actually uses the generics features of
Java 5.0 and implements a parameterized version of the interface:
Comparable<Circle>, but we can ignore that
fact until Chapter 4.) The purpose of
Comparable and its compareTo( )
method is to allow instances of a class to be compared to each
other in the way that the <,
<=, > and
>= operators compare numbers. If a class
implements Comparable, we can say that one
instance is less than, greater than, or equal to another instance.
Instances of a Comparable class can be sorted.

Since compareTo( ) is defined by an interface, the
Object class does not provide any default
implementation. It is up to each individual class to determine
whether and how its instances should be ordered and to include a
compareTo() method that implements that ordering.
The ordering defined by Example 3-6 compares
Circle objects as if they were words on a page.
Circles are first ordered from top to bottom: circles with larger Y
coordinates are less than circles with smaller Y coordinates. If two
circles have the same Y coordinate, they are ordered from left to
right. A circle with a smaller X coordinate is less than a circle
with a larger X coordinate. Finally, if two circles have the same X
and Y coordinates, they are compared by radius. The circle with the
smaller radius is smaller. Notice that under this ordering, two
circles are equal only if all three of their fields are equal. This
means that the ordering defined by compareTo() is
consistent with the equality defined by equals().
This is very desirable (but not strictly required).

The compareTo( ) method returns an
int value that requires further explanation.
compareTo() should return a negative number if the
this object is less than the object passed to it.
It should return 0 if the two objects are equal. And
compareTo() should return a positive number if
this is greater than the method argument.


3.8.5. clone()


Object defines a method named
clone()
whose
purpose is to return an object with fields set identically to those
of the current object. This is an unusual method for two reasons.
First, it works only if the class implements
the
java.lang.Cloneable interface.
Cloneable does not define any methods, so
implementing it is simply a matter of listing it in the
implements clause of the class signature. The
other unusual feature of clone() is that it is
declared protected
(see Section 3.6 earlier in this
chapter). This means that subclasses of Object can
call and override Object.clone(), but other code
cannot call it. Therefore, if you want your object to be cloneable,
you must implement Cloneable and override the
clone() method, making it
public.

The Circle class of Example 3-6
does not implement Cloneable; instead it provides
a

copy constructor for making copies of
Circle objects:

Circle original = new Circle(1, 2, 3);  // regular constructor
Circle copy = new Circle(original); // copy constructor

It can be difficult to implement clone( )
correctly, and it is usually easier and safer to provide a copy
constructor. To make the Circle class cloneable,
you would add Cloneable to the
implements clause and add the following method to
the class body:

@Override public Object clone() {
try { return super.clone(); }
catch(CloneNotSupportedException e) { throw new AssertionError(e); }
}

See

Effective Java Programming Guide by Joshua
Bloch for a detailed discussion of the ins and outs of
clone() and
Cloneable.


/ 1191