M-2 (Java)
M-2 (Java)
Declaring Objects
Here, class-var is a variable of the class type being created. The classname is the
When you create a class, you are creating a new data type.
name of the class that is being instantiated.
However, obtaining objects of a class is a two-step process.
The class name followed by parentheses specifies the constructor for the class.
First, you must declare a variable of the class type. This variable does not define an
A constructor defines what occurs when an object of a class is created.
object. Instead, it is simply a variable that can refer to an object.
Constructors are an important part of all classes and have many significant attributes.
Second, you must acquire an actual, physical copy of the object and assign it to that
It is important to understand that new allocates memory for an object during run time.
variable. You can do this using the new operator.
The advantage of this approach is that your program can create as many or as few
The new operator dynamically allocates (that is, allocates at run time) memory for an
objects as it needs during the execution of your program.
object and returns a reference to it.
However, since memory is finite, it is possible that new will not be able to allocate
This reference is, more or less, the address in memory of the object allocated by new.
memory for an object because insufficient memory exists.
This reference is then stored in the variable.
If this happens, a run-time exception will occur.
Thus, in Java, all class objects must be dynamically allocated.
A class creates a new data type that can be used to create objects.
That is, a class creates a logical framework that defines the relationship between its Introducing methods
members. When you declare an object of a class, you are creating an instance of that
class. This is the general form of a method:
Thus, a class is a logical construct. An object has physical reality. type name(parameter-list) {
// body of method
Assigning Object Reference Variables }
Object reference variables act differently when an assignment takes place. Here, type specifies the type of data returned by the method. This can be any valid
Box b1 = new Box(); type, including class types that you create.
Box b2 = b1; If the method does not return a value, its return type must be void.
The name of the method is specified by name. This can be any legal identifier other
than those already used by other items within the current scope.
The parameter-list is a sequence of type and identifier pairs separated by commas.
Parameters are essentially variables that receive the value of the arguments passed to
the method when it is called.
If the method has no parameters, then the parameter list will be empty.
Methods that have a return type other than void return a value to the calling routine
using the following form of the return statement:
After this fragment executes, b1 and b2 will both refer to the same object.
return value;
The assignment of b1 to b2 did not allocate any memory or copy any part of the
Here, value is the value returned.
original object.
It simply makes b2 refer to the same object as does b1.
Adding a Method to the Box Class
Thus, any changes made to the object through b2 will affect the object to which b1
class Box {
is referring, since they are the same object.
double width;
Although b1 and b2 both refer to the same object, they are not linked in any other
double height;
way.
double depth;
Box b1 = new Box(); Box b2 = b1;
// display volume of a box
// ...
void volume() {
b1 = null;
System.out.print("Volume is ");
System.out.println(width * height * depth);
Here, b1 has been set to null, but b2 still points to the original object.
}
}
class BoxDemo3 {
public static void main(String args[]) {
Box mybox1 = new Box(); double height;
// assign values to mybox1's instance variables double depth;
mybox1.width = 10; // compute and return volume
mybox1.height = 20; double volume() {
mybox1.depth = 15; return width * height * depth;
// display volume of first box }
mybox1.volume(); }
} class BoxDemo4 {
} public static void main(String args[]) {
This program generates the following output, which is the same as the previous version. Box mybox1 = new Box();
Volume is 3000.0 double vol;
Volume is 162.0 // assign values to mybox1's instance variables
mybox1.width = 10;
Look closely at the following two lines of code: mybox1.height = 20;
mybox1.volume(); mybox1.depth = 15;
The first line here invokes the volume( ) method on mybox1. // get volume of first box
That is, it calls volume( ) relative to the mybox1 object, using the object’s name vol = mybox1.volume();
followed by the dot operator. System.out.println("Volume is " + vol);
Thus, the call to mybox1.volume( ) displays the volume of the box defined by }
mybox1, }
There is something very important to notice inside the volume( ) method: the instance As you can see, when volume( ) is called, it is put on the right side of an assignment
variables width, height, and depth are referred to directly, without preceding them statement.
with an object name or the dot operator. On the left is a variable, in this case vol, that will receive the value returned by
When a method uses an instance variable that is defined by its class, it does so volume( ).
directly, without explicit reference to an object and without use of the dot operator. Thus, after vol = mybox1.volume(); executes, the value of mybox1.volume( ) is
This is easy to understand if you think about it. Amethod is always invoked relative to 3,000 and this value then is stored in vol.
some object of its class. Once this invocation has occurred, the object is known.
There are two important things to understand about returning values:
Returning a Value The type of data returned by a method must be compatible with the return type
While the implementation of volume( ) does move the computation of a box’s volume specified by the method. For example, if the return type of some method is boolean,
inside the Box class where it belongs, it is not the best way to do it. you could not return an integer.
class Box { The variable receiving the value returned by a method (such as vol, in this case) must
double width; also be compatible with the return type specified for the method.
Adding a Method That Takes Parameters An argument is a value that is passed to a method when it is Invoked.
While some methods don’t need parameters, most do. Parameters allow a method to For example, square(100) passes 100 as an argument. Inside square( ), the parameter
be generalized. i receives that value.
That is, a parameterized method can operate on a variety of data and/or be used in a Thus, a better approach to setting the dimensions of a box is to create a method that
number of slightly different situations takes the dimensions of a box in its parameters and sets each instance variable
appropriately.
int square() This concept is implemented by the following program:
{ // This program uses a parameterized method.
return 10 * 10; class Box {
} double width;
While this method does, indeed, return the value of 10 squared, its use is very limited. double height;
However, if you modify the method so that it takes a parameter, as shown next, then double depth;
you can make square( ) much more useful. // compute and return volume
int square(int i) double volume() {
{ return width * height * depth;
return i * i; }
} // sets dimensions of box
Now, square( ) will return the square of whatever value it is called with. That is, void setDim(double w, double h, double d) {
square( ) is now a general-purpose method that can compute the square of any integer width = w;
value, rather than just 10. height = h;
Here is an example: depth = d;
int x, y; }
x = square(5); // x equals 25 }
x = square(9); // x equals 81 class BoxDemo5 {
y = 2; public static void main(String args[]) {
x = square(y); // x equals 4 Box mybox1 = new Box();
In the first call to square( ), the value 5 will be passed into parameter i. Box mybox2 = new Box();
In the second call, I will receive the value 9. double vol;
The third invocation passes the value of y, which is 2 in this example. // initialize each box
As these examples show, square( ) is able to return the square of whatever data it is mybox1.setDim(10, 20, 15);
passed mybox2.setDim(3, 6, 9);
A parameter is a variable defined by a method that receives a value when the method // get volume of first box
is called. For example, in square( ), i is a parameter. vol = mybox1.volume();
System.out.println("Volume is " + vol); double depth;
// get volume of second box // This is the constructor for Box.
vol = mybox2.volume(); Box() {
System.out.println("Volume is " + vol); System.out.println("Constructing Box");
} width = 10;
} height = 10;
As you can see, the setDim( ) method is used to set the dimensions of each box. For depth = 10;
example, when mybox1.setDim(10, 20, 15); is executed, 10 is copied into parameter }
w, 20 is copied into h, and 15 is copied into d. // compute and return volume
Inside setDim( ) the values of w, h, and d are then assigned to width, height, and double volume() {
depth, respectively. return width * height * depth;
}
Constructors }
class BoxDemo6 {
It can be tedious to initialize all of the variables in a class each time an instance is
public static void main(String args[]) {
created.
// declare, allocate, and initialize Box objects
Even when you add convenience functions like setDim( ), it would be simpler and
Box mybox1 = new Box();
more concise to have all of the setup done at the time the object is first created.
Box mybox2 = new Box();
Because the requirement for initialization is so common, Java allows objects to
double vol;
initialize themselves when they are created.
// get volume of first box
This automatic initialization is performed through the use of a constructor.
vol = mybox1.volume();
A constructor initializes an object immediately upon creation.
System.out.println("Volume is " + vol);
It has the same name as the class in which it resides and is syntactically similar to a
// get volume of second box
method.
vol = mybox2.volume();
Once defined, the constructor is automatically called immediately after the object is
System.out.println("Volume is " + vol);
created, before the new operator completes.
}
Constructors look a little strange because they have no return type, not even void.
}
This is because the implicit return type of a class’ constructor is the class type itself.
When this program is run, it generates the following results:
It is the constructor’s job to initialize the internal state of an object so that the code
Constructing Box
creating an instance will have a fully initialized, usable object immediately.
Constructing Box
Volume is 1000.0
class Box {
Volume is 1000.0
double width;
double height;
class-var = new classname( ); Box mybox1 = new Box(10, 20, 15);
Now you can understand why the parentheses are needed after the class name. What Box mybox2 = new Box(3, 6, 9);
is actually happening is that the constructor for the class is being called. Thus, in the double vol;
line // get volume of first box
Box mybox1 = new Box(); vol = mybox1.volume();
new Box( ) is calling the Box( ) constructor new . System.out.println("Volume is " + vol);
When you do not explicitly define a constructor for a class, then Java creates a default // get volume of second box
constructor for the class vol = mybox2.volume();
System.out.println("Volume is " + vol);
Parameterized Constructors }
}
While the Box( ) constructor in the preceding example does initialize a Box object, it The output from this program is shown here:
is not very useful—all boxes have the same dimensions. Volume is 3000.0
What is needed is a way to construct Box objects of various dimensions. Volume is 162.0
Sometimes an object will need to perform some action when it is destroyed. For System.out.println("Stack is full.");
example, if an object is holding some non-Java resource such as a file handle or else
character font, then you might want to make sure these resources are freed before an stck[++top] = item;
object is destroyed. }
To handle such situations, Java provides a mechanism called finalization. // Pop an item from the stack
int pop() { 2
if(top < 0) { 1
System.out.println("Stack underflow."); 0
return 0; Stack in mystack2:
} 19
else 18
return stck[top--]; 17
} 16
} 15
class TestStack { 14
public static void main(String args[]) { 13
Stack mystack1 = new Stack(); 12
Stack mystack2 = new Stack(); 11
// push some numbers onto the stack 10
for(int i=0; i<10; i++) mystack1.push(i);
for(int i=10; i<20; i++) mystack2.push(i); Overloading Methods
// pop those numbers off the stack In Java it is possible to define two or more methods within the same class that share
System.out.println("Stack in mystack1:"); the same name, as long as their parameter declarations are different.
for(int i=0; i<10; i++) When this is the case, the methods are said to be overloaded, and the process is
System.out.println(mystack1.pop()); referred to as method overloading.
System.out.println("Stack in mystack2:"); Method overloading is one of the ways that Java supports polymorphism.
for(int i=0; i<10; i++) When an overloaded method is invoked, Java uses the type and/or number of
System.out.println(mystack2.pop()); arguments as its guide to determine which version of the overloaded method to
} actually call.
}
Thus, overloaded methods must differ in the type and/or number of their parameters.
This program generates the following output:
While overloaded methods may have different return types, the return type alone is
Stack in mystack1:
insufficient to distinguish two versions of a method.
9
8
class OverloadDemo {
7
void test() {
6
System.out.println("No parameters");
5
}
4
// Overload test for one integer parameter.
3
void test(int a) { However, this match need not always be exact. In some cases, Java’s automatic type
System.out.println("a: " + a); conversions can play a role in overload resolution.
}
// Overload test for two integer parameters. For example, consider the following program:
void test(int a, int b) { // Automatic type conversions apply to overloading.
System.out.println("a and b: " + a + " " + b); class OverloadDemo {
} void test() {
// overload test for a double parameter System.out.println("No parameters");
double test(double a) { }
System.out.println("double a: " + a); // Overload test for two integer parameters.
return a*a; void test(int a, int b) {
} System.out.println("a and b: " + a + " " + b);
} }
class Overload { // overload test for a double parameter
public static void main(String args[]) { void test(double a) {
OverloadDemo ob = new OverloadDemo(); System.out.println("Inside test(double) a: " + a);
double result; }
// call all versions of test() }
ob.test(); class Overload {
ob.test(10); public static void main(String args[]) {
ob.test(10, 20); OverloadDemo ob = new OverloadDemo();
result = ob.test(123.25); int i = 88;
System.out.println("Result of ob.test(123.25): " + result); ob.test();
} ob.test(10, 20);
} ob.test(i); // this will invoke test(double)
This program generates the following output: ob.test(123.2); // this will invoke test(double)
No parameters }
a: 10 }
a and b: 10 20 This program generates the following output:
double a: 123.25 No parameters
Result of ob.test(123.25): 15190.5625 a and b: 10 20
Inside test(double) a: 88
When an overloaded method is called, Java looks for a match between the arguments Inside test(double) a: 123.2
used to call the method and the method’s parameters.
When test( ) is called with an integer argument inside Overload, no matching method // constructor used when no dimensions specified
is found. Box() {
However, Java can automatically convert an integer into a double, and this width = -1; // use -1 to indicate
conversion can be used to resolve the call. height = -1; // an uninitialized
Therefore, after test(int) is not found, Java elevates i to double and then calls depth = -1; // box
test(double). }
Of course, if test(int) had been defined, it would have been called instead. Java will // constructor used when cube is created
employ its automatic type conversions only if no exact match is found. Box(double len) {
Method overloading supports polymorphism because it is one way that Java width = height = depth = len;
implements the “one interface, multiple methods” paradigm. }
When you overload a method, each version of that method can perform any activity // compute and return volume
you desire. double volume() {
There is no rule stating that overloaded methods must relate to one another. return width * height * depth;
Thus, while you can use the same name to overload unrelated methods, you should }
In addition to overloading normal methods, you can also overload constructor Box mybox1 = new Box(10, 20, 15);
methods. In fact, for most real-world classes that you create, overloaded constructors Box mybox2 = new Box();
will be the norm, not the exception. Box mycube = new Box(7);
To understand why, let’s return to the Box class developed in the preceding chapter. double vol;
height = h; }
depth = d; }
The three println( ) statements refer to the two static variables a and b, as well as to }
the local variable x. }
Here is the output of the program: Here is the output of this program:
x = 42 b = 99
a=3
b = 12 Introducing final
A variable can be declared as final. Doing so prevents its contents from being
Outside of the class in which they are defined, static methods and variables can be modified. This means that you must initialize a final variable when it is declared.
used independently of any object. For example:
To do so, you need only specify the name of their class followed by the dot operator. final int FILE_NEW = 1;
For example, if you wish to call a static method from outside its class, you can do so final int FILE_OPEN = 2;
Here, classname is the name of the class in which the static method is declared. As final int FILE_QUIT = 5;
you can see, this format is similar to that used to call non-static methods through Subsequent parts of your program can now use FILE_OPEN, etc., as if they were
object-reference variables. constants, without fear that a value has been changed.
A static variable can be accessed in the same way—by use of the dot operator on the It is a common coding convention to choose all uppercase identifiers for final
name of the class. This is how Java implements a controlled version of global variables.
methods and global variables. Variables declared as final do not occupy memory on a per-instance basis. Thus, a
Here is an example. Inside main( ), the static method callme( ) and the static variable final variable is essentially a constant.
b are accessed through their class name StaticDemo. The keyword final can also be applied to methods, but its meaning is substantially
class StaticDemo { different than when it is applied to variables.
static int a = 42; Introducing Nested and Inner Classes
static int b = 99; It is possible to define a class within another class; such classes are known as
static void callme() { nested classes. The scope of a nested class is bounded by the scope of its
enclosing class.
System.out.println("a = " + a); A nested class has access to the members, including private members, of the class in
} which it is nested. However, the enclosing class does not have access to the members of the
nested class. A nested class that is declared directly within its enclosing class scope is a
} member of its enclosing class. It is also possible to declare a nested class that is local to a
block.
There are two types of nested classes: static and non-static. A static nested class is one
that has the static modifier applied. Because it is static, it must access the non-static
members of its enclosing class through an object.
class Outerclass
{
…..
Class Nestedclass
{
……
}
}