Вы находитесь на странице: 1из 16

Advanced Core JAVA

Module 1
Class Design
Objectives :
Upon completion of this module, you should be able to :

Define inheritance, polymorphism, overloading, overriding and virtual method invocation


Use the access modifiers protected and the default (package friendly)
Describe the concepts of constructor and method overloading
Describe the complete object construction and initialization operation

This module describes the object-oriented paradigm and the object-oriented features of
the Java programming language.

CETTM,MTNL,Mumbai

I 683

1 PA

Advanced Core JAVA

Subclassing
Object Oriented Programming provides for inheritance. The use of inheritance is to
create specialized classes. The specialized classes derived from the parent class (super classgeneral class) are called sub-classes or child classes.
In case of inheritance of living things the offspring is a specialized one which takes some
characters from father and some from mother. This type of inheritance from more than one
parent is called multiple inheritance. The main goal of inheritance is evolution. Evolution means
creating more specialized one or more customized one.
Many languages provide for the multiple inheritance in sub class formation. If sub class
is not properly defined then this type of inheritance creates conflicts between inherited
Properties. In living things the inheritance of same property is controlled by the differentiation of
recessive and dominant genes. The property of the dominant gene is expressed in the offspring.
As there is no such provision in computer languages, the common properties of the parent
classes are to be controlled by the programmer. This puts a lot of restriction and some times the
process is disastrous while programming. Hence Java does not provide for multiple inheritance.
The multiple inheritance provides for incorporating the properties of different classes in one sub
class which is very useful many times. Hence, in Java this feature is also retained with the use
of interfaces. This will be dealt with afterwards.
In Java, a subclass can be descended from only one parent class. Hence Java only
supports single inheritance. But there is no restriction in creating many subclasses from a single
parent class. Whenever a subclass is created from a parent class then all the properties of that
parent class will be automatically assigned to the subclass.
Code reusability is a key advantage of object-oriented languages over non-objectoriented languages. Inheritance is the mechanism by which this is achieved. An object (of
subclass) can inherit the variables and methods of parent object (super class). Sub class can
keep those methods and variables which it wants, and replace those which it doesn't want.
Hence in the sub class the programmer need not write any code for the parent properties for
which code is written in the parent class.

Defining a subclass
The key word extends is used to define a sub class. The keyword should be followed by
the name of the super class of which the sub class is being extended. The immediate subclass
is called direct subclass and the immediate super class is called direct super class. The
hierarchy of classes can go from subclass to subclass. All the sub classes in the hierarchy
downwards retain the properties acquired or incorporated by all the super classes. It means that
if a subclass C is extended from a class B and the class B itself is a subclass of A then class C
has all the properties (methods and variables) of class B and class A.
Ex :
class A
{
statements
}
class B extends A
{
statements
// This class has all the properties(methods and variables) of class A
// This class has also created properties of its own due to the statements
written in it.
}
class C extends B
{

Advanced Core JAVA

statements

// This class has all the properties(methods and variables) of class A and
B
// This class has also created properties of its own due to the statements
written in it.

}
The Object class is the super most class in Java. Hence the class Object cannot have
the extends clause in its class definition. All other classes in Java are either direct subclasses of
Object class or subsequent subclasses. If any class does not contain extends clause in its
class definition then that class must be a direct subclass of the class Object.
For example, let us have the SavingsAccount class so that it has attributes
accountNumber, accountName, address, drawingPower and minimumBalance.
Ex. : Refer Program 1.1
Now suppose we also need a class CurrentAccount. A CurrentAccount also should
have attributes accountNumber, accountName, address, drawingPower and overDraft and
many other properties we can represent with fields.
Ex. : Refer Program 1.2
If we keenly see these two classes then it is evident that many features (methods and
fields) are overlapping. In this way, suppose we have to create many different types of accounts
then many features which are common to each account are to be repeated in each class.
Suppose that it is possible to keep all the common features in one class and those can be used
in other classes without rewriting them. Then we need to write only specialized features in other
classes and common features can be inherited from the class where those features are written.
As there is no limit to this reusability we can save lot of resources and coding efforts. This
reusability feature is incorporated in inheritance.
Based on this let us create a super class named Customer which contains all the
common features of the accounts. Then we will create different classes of accounts customized
in some way. For that we create two classes for Savings Account and Current Account with
inherited properties from Customer.
Ex. : Refer Program 1.3 (Customer class)
Ex. : Refer Program 1.4 (SubclassSavingsAccount class)
Ex. : Refer Program 1.5 (SubclassCurrentAccount class)
In the above examples we have created two subclasses of Customer. Both the classes
created are direct subclasses of Customer class. There is nothing to stop us from going further.
We can define subclasses of SubclassSavingsAccount for Savings Account with passbook
and more. For example, we create one SavingsAccountPassbook class for the issue of pass
books. Here change is only for pass books.
This SavingsAccountPassbook class not only inherits from its immediate superclass,
SubclassSavingsAccount, but also from SubclassSavingsAccount's superclass,
Customer. Thus the SavingsAccountPassbook class has also an account Number, Name of
the account holder, address of the account holder, account holders drawing power and so on.
This is called multilevel inheritance. There's no limit to this chain of inheritance, though getting
more than four or five classes deep makes code excessively complex.
Ex. : Refer Program 1.6

Access Control

CETTM,MTNL,Mumbai

I 683

3 PA

Advanced Core JAVA

While programming, if the programmer gives access to all the variables and methods he
uses, then it may cause bugs or corruption. Some unknown function can change the value of a
variable when the programmer does not expect it to change. This plays all sorts of havoc.
Most OOP languages including Java allow you to protect variables from external
modification. This allows you to guarantee that our class remains consistent. For example, in the
Customer class we'd like to make sure that no block of code from some other class is allowed
to make the drawingPower greater than the assigned value while constructing the object.
Therefore we want a way to make the following illegal from other classes.

sb.drawingPower = 10000.0;
If the above code works then it means that a sb object is made with drawingPower of
Rs. 5000.0 but subsequently that sb is made to operate with drawingPower Rs. 10000.0. Thus
the whole idea of making a consistent Customer class fails.
Therefore the variable drawingPower should not be changeable from outside the class.
If the variable drawingPower is not approachable (accessible) from outside the class then its
value can not be changed. This type of access restrictions are to be imposed on methods and
variables to keep the program consistent. The different types of access permission may be
required for giving access to different persons. Based on this principle Java provides four types
of access modifiers. The Java methods and variables can be at one of the four access levels ie.
public, private, protected or unspecified (default). The Java classes can be either at public
level or at default level.

Modifier
private
default
protected
public

Same Class
Yes
Yes
Yes
Yes

Accessibility Criteria
Same Package Subclass

Universe

Yes
Yes
Yes

Yes

Yes
Yes

Hence a variable or a method marked private is accessible from the same class only.
The variable or the method which does not have any access modifier means it is at default
access modifier level. Such variable or method is accessible within all the classes of a package.
Hence default modifier is also called package friendly access modifier.
The access modifier protected is friendlier than default modifier. It allows the methods
and variables to be accessible from within all the classes of the package and from the
subclasses residing in the other packages also.
Hence while using the access modifiers, first it is to be decided that how far the method
or the variable is required to be seen for handling and accordingly appropriate access modifier is
to be used.
Ex. : Refer Programs 1.7.1, 1.7.2, 1.7.3, 1.7.4 and 1.7.5

Overriding Methods
In addition to producing a new class based on an old one by adding additional features,
you can modify existing behavior of the parent class.

Advanced Core JAVA

If a method is defined in a subclass so that the name, return type, and argument list
match exactly those of a method in the parent class, then the new method is said to override the
old one.
In J2SE version 5.0, these matching rules have changed slightly. The return type of the
overriding method can now be a subtype of the return type in inherited method.
Over riding is restricted to visible methods of super class. Method of the super class with
default access modifier is not visible in the subclass residing in another package and hence
cannot be overridden. Similarly final, static or private methods of the super class cannot be
overridden.
Suppose that one day you've just finished your Balance class. It's been plugged into your
banking transactions which is doing merrily transacting customers business. Then your pointy
haired boss rolls in the door, and tells you that he needs the Balance class to keep minimum
balance Rs. 10000.0 instead of Rs. 5000.0.
What are you going to do? Your first reaction may be to change the class that you
already wrote so that it enhances the minimum balance. However you're using that class
elsewhere and things will break if you change it.
You could create a completely new class in a different file, either by starting from scratch
or by copying and pasting. This would work, but it would mean that if you found a bug in the
Balance class now you'd have to fix it in two files. And if you wanted to add new methods to the
Balance class, you'd have to add them in two files. Still this is the best you could do if you were
writing in C or some other traditional language.
The object oriented solution to this problem is to define a new class, call it
ModifiedBalance, which inherits from Balance class and imposes the additional constraint that
a minimum balance may not go below Rs. 10000.0.
To do this you'll need to adjust the place that minimumBalance can be changed, the
withdraw() method. Hence the withdraw() method must be overridden. This means the
subclass has a method with the same signature as the method in the superclass.
The first thing to note about this class is what it doesn't have, balance field. This is
provided by the superclass Balance. Nothing about fields (or methods which is not overridden)
has changed so they don't need to be repeated here.
Next look at the withdraw() method. This is different than the withdraw() method in
Balance. It imposes the additional constraint.
Ex. : Refer Programs 1.8.1, 1.8.2, 1.8.3 and 1.8.4

Overridden Methods Cannot Be Less Accessible


The method-name and the order of arguments of a child method must be identical to
those of the method in the parent class while overriding the parent version of the method.
Furthermore, an overriding method cannot be less accessible than the method it overrides.
Ex. : Refer Programs 1.8.1 and 1.8.3

Adding New Methods


A subclass isn't restricted to changing the behavior of its super class. It can also add
completely new methods and fields that are not shared with the super class. For instance if a
class represents a user of a multi-user database, the user class might start off with no access.

CETTM,MTNL,Mumbai

I 683

5 PA

Advanced Core JAVA

Secretaries could be given read-only access. Therefore the secretary class would have
additional methods to read data that aren't part of the super class.
Data entry clerks might be allowed to read the database and to create new records but
not to modify old records. Therefore the data entry class would inherit from the secretary class
and have methods to allow adding new records. A supervisor class would inherit from the data
entry class and also have methods that allow modification of existing records. Finally a database
manager would inherit from supervisor, but have new methods that allowed database managers
to change the structure of the database.
As a practical example, recall that the SavingsAccount added a minimumBalance
field and a minimumBalanceGetter() method that the Customer class didn't have.
Ex. : Refer Program 1.4

Invoking Super Class Methods


A subclass method can invoke a super class method using the super keyword. The
super keyword refers to the super class of the class in which the keyword is used. It is used to
refer to the member variables or the methods of the super class.
A call of the form super.method () invokes the entire behavior, along with any side
effects of the method that would have been invoked if the object had been of the parent class
type. The method does not have to be defined in that parent class. It could have been inherited
from some class even further up the hierarchy.
Ex. : Refer Program 1.8.3

Polymorphism
SubclassSavingsAccount is a subclass of Customer. SavingsAccountPassbook is a
subclass of SubclassSavingsAccount and Polymorphism is a subclass of
SavingsAccountPassbook. Polymorphism class implements the interface MyInterface. If you
instantiate Polymorphism with new, you can assign that object to any of the variables of type
Polymorphism or SavingsAccountPassbook or SubclassSavingsAccount or Customer or
MyInterface. As Object class is the super class for all the classes of JAVA, the object of
Polymorphism can be assigned to a variable of Object type. This use of a subclass object in
place of a super class object is a form of polymorphism.
The converse is not true. Therefore an object of super class cannot be assigned to a
variable of subclass type.
An object has only one form (the one that is given to it when constructed). Hence object
is constructor dependant. However, a variable is polymorphic because it can refer to objects of
different forms.
The Java programming language, like most object-oriented languages, actually permits
you to refer to an object with a variable that is one of the parent class types or of implemented
interface type. The interface might have been implemented in the parent class hierarchy.
The type of reference variable cannot be changed but the object that variable refers can
be changed to a compatible object. The reference variables type decides the methods of which
class can be executed.
Ex. : Refer Program 1.9

Virtual Method Invocation

Advanced Core JAVA

The following scenario is true :


VirtualMethodInvocation vmi = new VirtualMethodInvocation();
SavingsAccountPassbook sap = new SavingsAccountPassbook();
If you ask for vmi.amountBalanceGetter() and sap.amountBalanceGetter() , you invoke
different behaviors. The VirtualMethodInvocation object executes the version of
amountBalanceGetter() associated with the VirtualMethodInvocation class, and the
SavingsAccountPassbook object executes the version of amountBalanceGetter() associated
with the SavingsAccountPassbook class.
What happens if you have :
SavingsAccountPassbook sap = new VirtualMethodInvocation();
sap. amountBalanceGetter();
or something similar, such as a general method argument or an item from a
heterogeneous collection.
In fact, you get the behavior associated with the object to which the variable refers at
runtime. The behavior is not determined by the compile time type of the variable. This is an
aspect of polymorphism, and is an important feature of object-oriented languages. This behavior
is often referred to as virtual method invocation.
In the previous example, the sap. amountBalanceGetter() method executed is from the
object's real type, VirtualMethodInvocation.
At compile time the compiler verifies the type of the reference variable storing the object.
The compiler does not verify the real object inside the reference variable. If the type of the
reference variable is such that the class (the type) is visible at that location then the compiler
compiles that code. At run time the JVM verifies the actual object (constructor class) and the
behaviour (method) of that object (class) is run irrespective of the type of the reference variable.
This behaviour of JAVA is known as virtual method invocation.
SavingsAccountPassbook sap = new VirtualMethodInvocation();
sap. AmountBalanceGetter();
For example in the above code the type of the reference variable is
SavingsAccountPassbook.
The
actual
object
(constructor
class)
is
of
VirtualMethodInvocation.
While
compilation
the
compiler
verifies
whether
AmountBalanceGetter() method is available (visible) in SavingsAccountPassbook class. If
not then there will be a compilation error else the code compiles. At run time JVM will not verify
the SavingsAccountPassbook class (type of the reference variable). Instead it verifies the
actual
object
(
VirtualMethodInvocation
class)
and
runs
the
behaviour
(AmountBalanceGetter() method) of the object class.

If you are a C++ programmer, there is an important distinction to be drawn between the
Java programming language and C++. In C++, you get this behavior only if you mark the
method as virtual in the source. In pure object-oriented languages, however, this is not normal.
C++ does this to increase execution speed.
Ex. : Refer Program 1.10

Homogeneous Collections

CETTM,MTNL,Mumbai

I 683

7 PA

Advanced Core JAVA

You can create collections of objects that have a common class. Such collections are
called homogeneous collections.
For example :
Customer[] csa = new Customer[4];
csa [0] = new Customer();
csa [1] = new Customer();
csa [2] = new Customer();
csa [3] = new Customer();
Ex. : Refer Program 1.11

Heterogeneous Collections
The Java programming language has an Object class, which is the parent class of all
JAVA classes. So you can create virtual objects of either parent class or Object class and make
collections of all kinds of elements. These collections are called heterogeneous collections.
A heterogeneous collection is a collection of dissimilar items. In object-oriented
languages, you can create collections of many items. All have a common ancestor class i.e. the
Object class.
Every class is a subclass of Object, so you can use an array of Object as a container for
any combination of objects. The only items that cannot be added to an array of Object are
primitive variables. However, you can create objects from primitive data using wrapper classes,
as described in "Wrapper Classes"
Ex. : Refer Program 1.10

Instanceof Operator
Given that you can pass objects around using references to their parent classes,
sometimes you might want to know what actual objects you have. This is the purpose of the
instanceof operator.
Suppose the class hierarchy is extended so that you have the following :
public class Customer extends Object
public class SubclassSavingsAccount extends Customer
public class SavingsAccountPassbook extends SubclassSavingsAccount
public class VirtualMethodInvocation extends SavingsAccountPassbook
Remember that, while acceptable, extends Object is redundant. It is shown here only as
a reminder.
If you receive an object using a reference of type Customer, it might turn out to be a
SubclassSavingsAccount or a SavingsAccountPassbook. You can test it by using
instanceof operator.
If test for higher class hierarchy instance is to be made and an instance of its subclass is
also is to be tested then the instance of subclass is to be tested prior to instance of parent class
else parent class testing includes instance of subclass also. In this example the instance of
VirtualMethodInvocation is to be tested prior to the instance of SavingsAccountPassbook
class and so on.
In C++, you can do something similar using runtime-type information (RTTI).

Advanced Core JAVA

Ex. : Refer Program 1.10

Casting Objects
In circumstances where you have received a reference to a parent class, and you have
determined that the object is, in fact, a particular subclass by using the instanceof operator, you
can access the full functionality of the object by casting the reference.
If you do not make the cast, an attempt to execute cs[i].passBookHolderGetter() would
fail because the compiler cannot locate a method called passBookHolderGetter() in the
Customer class.
If you do not make the test using instanceof, you run the risk of the cast failing.
Generally, any attempt to cast an object reference is subjected to several checks :
1. Casts upward in the class hierarchy are always permitted and, in fact, do not
require the cast operator. They can be done by simple assignment.
2. For downward casts, the compiler must be satisfied that the cast is at least
possible. For example, any attempt to cast a SavingsAccount reference to a
Customer reference is not permitted, because the SavingsAccount is not a
Customer. The class to which the cast is taking place must be some subclass of
the current reference type.
3. In other cases if the compiler permits the cast, then the object type is checked at
runtime. For example, if it turns out that the instanceof check is omitted from the
source, and the object being cast is not in fact an object of the type it is being
cast to, then a runtime error (exception) occurs.
Ex. : Refer Program 1.12

Methods Using Variable Arguments (Overloading Methods)


Overloading is when the same method or operator can be used on many different types
of data. For instance the + sign is used to add integers as well as concatenate strings. The plus
sign behaves differently depending on the type of its arguments. Therefore the plus sign is
inherently overloaded.
In some circumstances, you might want to write several methods in the same class that
do the same basic job with different arguments.
Consider a simple method that is intended to output a textual representation of its
argument. This method could be called println(). Now suppose that you need a different print
method for printing each of the int, float, and String types. This is reasonable, because the
various data types require different formatting and probably, varied handling. You could create
three methods, called printlnInt(), printlnFloat() and printlnString() , respectively. However,
this is tedious.
The Java programming language permits you to reuse a method name for more than
one method. This works only if there is something in the circumstances under which the call
made distinguishes the method that is needed. In the case of the three print methods, this
distinction is based on the number and type of the arguments.
By reusing the method name, you end up with the following methods :
public void println(int i)
public void println(float f)
public void println(String s)

CETTM,MTNL,Mumbai

I 683

9 PA

Advanced Core JAVA

When you write code to call one of these methods, the appropriate method is chosen
according to the type of argument or arguments you supply.
Two rules apply to overloaded methods :

1. Argument lists must differ


The argument lists of the calling statement must differ enough to allow unambiguous
determination of the proper method to call. Normal widening promotions (for example, float to
double) might be applied; but this can cause confusion under some conditions.

2. Return types can be different


The return type of the methods can be different, but it is not sufficient for the return type
to be the only difference. The argument lists of overloaded methods must differ. A variation on
overloading is when you need a method that takes any number of arguments of the same type.
For example, imagine you need to create a method that calculates the average of a set
of integers.
You could define the following methods:
public class Statistics {
public float average(int x1, int x2) {}
public float average(int x1, int x2, int x3) {}
public float average(int x1, int x2, int x3, int x4) {}
}
These methods can be invoked as follows:
Statistics stats = new Statistics();
float gradePointAverage = stats.average(4, 3, 4);
float averageAge = stats.average(24, 32, 27, 18) ;
Ex. : Refer Program 1.13

Varargs Method
The three overloaded methods all share the same functionality. It would be nice to
collapse these methods into one method. J25E version 5.0 now provides a feature, called
varargs or variable arguments, to enable you to write a more generic method.

public class Statistics {


public float average (int nums) {
int sum = 0;
for ( int x : nums ) {
sum += x;
}
return (( float) sum) / nums.length;
}
}
This new varargs method can be invoked in the same manner as the suite of overloaded
methods. Notice that the nums argument is an actual array object of type int []. The ellipse (...)
defines the nums as an array. This permits the method to iterate over the elements and to get
the number of elements (that is, the length of the array).

Advanced Core JAVA

Ex. : Refer Program 1.14


Ex. : Refer Program 1.15

Constructors Are Not Inherited


Although a subclass inherits all of the methods and variables (except private ones) from
a parent class, it does not inherit constructors.
There are only two ways in which a class can gain a constructor; either you write the
constructor or because you have not written any constructor the class has a single default
constructor. A parent constructor is always called in addition to a child constructor. This is
described in detail later in this module.
The constructor is a little more complicated. First note that if you are going to use a nondefault constructor, that is a constructor with arguments, you do need to write a constructor for
the subclass, even if it is just going to do the exact same thing as the matching constructor in
the superclass. You cannot simply inherit the constructor of super class Customer in
SubclassSavingsAccount because that parent constructor is named as Customer() whereas
one in SubclassSavingsAccount must be named as SubclassSavingsAccount().

Invoking Parent Class Constructors


Like methods, constructors can call the non-private constructors of its immediate
superclass.
Often you define a constructor in parent class that takes arguments and you want to use
those arguments to control the construction of the parent part of an object. Then you can invoke
that particular parent class constructor as part of a child class initialization by using the keyword
super(args list) from the child constructor's first line. To control the invocation of the specific
constructor, you must provide the appropriate arguments to super(). When there is no call to
super with arguments, the parent constructor with zero arguments is called implicitly. In this
case, if there is no parent constructor with zero arguments, a compiler error results.
The call to super() can take any number of arguments appropriate to the various
constructors available in the parent class, but it must be the first statement in the constructor.
Ex. : Refer Program 1.16

Constructing and Initializing Objects


Object initialization is a rather complex process. First, the memory for the complete
object is allocated and the default values for the instance variables are assigned. Second, the
top-level constructor is called and follows these steps recursively down the inheritance tree:
1. Bind constructor parameters.
2. If explicit this(), call recursively, and then skip to Step 5.
3. Call recursively the implicit or explicit super(), except for Object because Object
has no parent class.
4. Execute the explicit instance variable initializers.
5. Execute the body of the current constructor.
Ex. :

Refer Program 1.16


Refer Program 1.4

CETTM,MTNL,Mumbai

I 683

11 PA

Advanced Core JAVA

The Object Class


The Object class is the root of all classes in the Java technology programming language.
If a class is declared with no extends clause, then the compiler adds implicitly the code extends
Object to the declaration.
For example:
public class Customer{
/ / more code here
}
is equivalent to :
public class Customer extends Object {
/ / more code here
}
This enables you to override several methods inherited from the Object class. The
following sections describe two important methods of Object class.

The Methods of java.lang.Object


java.lang.Object provides a number of methods that are common to all objects. toString()
is the most common such method. Since the default toString() method only produces the name
of the class, you should override it in all classes you define.

public final Class getClass()


public int hashCode()
public boolean equals(Object obj)
protected Object clone() throws CloneNotSupportedException
public String toString()
public final void notify()
public final void notifyAll()
public final void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanoseconds) throws InterruptedException
public final void wait() throws InterruptedException
protected void finalize() throws Throwable

toString() Methods
Print methods are common in some languages, but most Java programs operate
differently. You can use System.out.println() to print any object. However for good results your
class should have a toString() method that formats the object's data in a sensible way and
returns a string. Otherwise all that is printed is the name of the class which is normally not what
you want. For example, a good toString() method for the CustomerModified class might be
public String toString() {
return (Account Number : + this.accountNumber + Account Name : +
this.accountName + Address : + this.address + Drawing Power : + this.drawingPower);
}

Using toString() Methods


If an object of a class is put for printing in println() method then we get Class Name and a
hexadecimal code which is meaningless as far as user is concerned. To get a meaningful
information while printing an object, we have to override the toString method of Object class.

Advanced Core JAVA

Rules for toString() Methods

toString() methods should return a single line of text that does not contain any carriage
returns or linefeeds.
toString() methods are primarily for debugging.
toString() should not do a lot of fancy processing.
toString() methods should be quick.
The string returned by toString() should contain the name of the class, and names and
values of the fields that represent the state of the object, unless there are an excessive
number of such fields, in which case only the most important should be returned.

These rules are conventions, not requirements of the language.


Ex. : Refer Program 1.17

The equals() method


The equals() method of java.lang.Object acts the same as the == operator; that is, it
tests for object identity (test for equality of reference variables) rather than object equality (object
values). The implicit contract of the equals() method, however, is that it tests for equality
(equality of object values) rather than identity (equality of reference variables). Thus most
classes will override equals() method of Object class with a version that does comparisons, field
by field, before deciding whether to return true or false.
To elaborate, an object created by a clone() method (that is a copy of the object) should
pass the equals() test if neither the original nor the clone has changed since the clone was
created. However the clone will fail to be == to the original object.
For example, here is an equals() method you could use with reference to Customer
class. Two customers are equal if and only if their account numbers are equal, and that is what
this method tests for.
This example is particularly interesting because it demonstrates the impossibility of
writing a useful generic equals() method that tests equality for any object. It is not sufficient to
simply test for equality of all the fields of two objects. Because it is entirely possible that some of
the fields may not be relevant to the test for equality as in this example where changing the
Name of a customer or change of address does not change the actual account that is referring
to. Be careful to avoid this common mistake when writing equals() methods.
You do not need to test whether ob is null. null is never an instance of any class. null
instanceof Object returns false.
Ex. : Refer Program 1.18.2

The hashCode() method


Anytime you override equals() you should also override hashCode(). The hashCode()
method should ideally return the same int for any two objects that compare equal and a different
int for any two objects that don't compare equal, where equality is defined by the equals()
method. This is used as an index by the java.util.Hashtable class.
In the EqualsMethodModified example equality is determined exclusively by comparing
accountNumbers; therefore only the accountNumber field is used to determine the hash code.
Since accountNumber is a String, and since the String class has its own hashCode() method,
we can sponge off of that.

CETTM,MTNL,Mumbai

I 683

13 PA

Advanced Core JAVA

public int hashCode() {


return this.accountNumberGetter().hashCode();
}
Other times you may need to use the bitwise operators to merge hash codes for multiple
fields. There is also a variety of useful methods in the wrapper classes (java.lang.Double,
java.lang.Float, etc.) that converts primitive data types to integers that share the same bit string.
These can be used to hash primitive data types.
public int hashCode ( )
{
return (day ^ month ^ year) ;
}
Ex. : Refer Program 1.18.2

Wrapper Classes
The Java programming language does not look at primitive data types as objects. For
example, numerical, boolean and character data are treated in the primitive form for the sake of
efficiency.
However the Java programming language provides wrapper classes to manipulate
primitive data elements as objects. Such data elements are wrapped in an object created
around them. Each Java primitive data type has a corresponding wrapper class in the java.lang
package. Each wrapper class object encapsulates a single primitive value.

Primitive Data Type


boolean
byte
char

Wrapper Class
Boolean
Byte
Character

short

Short

int

Integer

long

Long

float

Float

double

Double

All the wrapper classes except Character have two constructors, one that takes the
primitive value and another that takes the String representation of the value.
For instance :
Integer i1 = new Integer(50);
Integer i2 = new Integer("50");
The Character class constructor takes a char type element as an argument :
Character c = new Character('A');

Advanced Core JAVA

This is called boxing.


int p2 = i1.intValue();
This is called un-boxing.
Wrapper objects are immutable. This means that once a wrapper object has a value
assigned to it, that value cannot be changed.
Ex. : Refer Program 1.19

The valueOf() method


All wrapper classes (except Character) define a static method called valueOf(), which
returns the wrapper object corresponding to the primitive value represented by the String
argument.
For instance :
Float f1 = Float.valueOf("1.5f");
The overloaded form of this method takes the base representation (binary, octal, or
hexadecimal) of the first argument as the second argument.
For instance:
Integer I = Integer.valueOf("10011110",2);
Ex. : Refer Program 1.19

Converting wrapper objects to primitives


All the numeric wrapper classes have six methods, which can be used to convert a
numeric wrapper to any primitive numeric type. These methods are byteValue, doubleValue,
floatValue, intValue, longValue, and shortValue.
An example is shown below:
Integer i = new Integer(20);
byte b = i.byteValue();
Ex. : Refer Program 1.19

Parser methods
The six parser methods are parseInt, parseDouble, parseFloat, parseLong, parseByte,
and parseShort. They take a String as the argument and convert it to the corresponding
primitive. They throw a NumberFormatException if the String is not properly formed.
For instance:
double d = Double.parseDouble("4.23");
It can also take a radix (base) as the second argument:
int i = Integer.parseInt("10011110",2);
Ex. : Refer Program 1.19

CETTM,MTNL,Mumbai

I 683

15 PA

Advanced Core JAVA

Base conversion
The Integer and Long wrapper classes have methods like toBinaryString() and
toOctalString(), which convert numbers in base 10 to other bases.
For instance:
String s = Integer.toHexString(25);
Ex. : Refer Program 1.19

Autoboxing of Primitive Types


If you have to change the primitive data types to their object equivalents (called boxing),
then you need to use the wrapper classes. Also to get the primitive data type from the object
reference (called unboxing), you need to use the wrapper class methods. All of this boxing and
unboxing can clutter up your code and thus make your code difficult to understand.
In J2SE version 5.0, the autoboxing feature enables you to assign and retrieve primitive
types without the need of the wrapper classes.
int pint = 420;
Integer wint = pint; // this is called autoboxing
int p2 = wint; // this is called autounboxing
The J2SE version 5.0 compiler will-now create the wrapper object automatically when
assigning a primitive to a variable of the wrapper class type. The compiler will also extract the
primitive value when assigning from a wrapper object to a primitive variable.
This can be done when passing parameters to methods or even within arithmetic
expressions.

Caution - Do not overuse the autoboxing feature. There is a hidden performance


impact when a value is autoboxed or autounboxed. Mixing primitives and wrapper objects in
arithmetic expressions within a tight loop might have a negative impact on the performance and
throughput of your applications.
Ex. : Refer Program 1.20

Вам также может понравиться