Unit-II
Introducing classes
The class is at the core of Java. It is the logical construct upon which the entire Java language is
built because it defines the shape and nature of an object. As such, the class forms the basis for
object-oriented programming in Java. Any concept you wish to implement in a Java program
must be encapsulated within a class.
Class fundamentals
The classes created in the preceding chapters primarily exist simply to encapsulate the main( )
method, which has been used to demonstrate the basics of the Java syntax. As you will see,
classes are substantially more powerful than the limited ones presented so far.
The general form of a class definition is shown here:
class classname {
type instance-variable1;
type instance-variable2;
// ...
type instance-variableN;
type methodname1(parameter-list) {
// body of method
}
type methodname2(parameter-list) {
// body of method
}
// ...
type methodnameN(parameter-list) {
// body of method
}
}
1
The data, or variables, defined within a class are called instance variables. The code is
contained within methods. Collectively, the methods and variables defined within a class are
called members of the class. In most classes, the instance variables are acted upon and accessed
by the methods defined for that class. Thus, it is the methods that determine how a class' data can
be used.
Example
class Box
{
double width;
double height;
double depth;
}
Declaring Objects
General form is
Class_name object_name = new Class_name()
Example
Box mybox = new Box();
This statement combines the two steps just described. It can be rewritten like this to show
each step more clearly:
Box mybox; // declare reference to object
mybox = new Box(); // allocate a Box object
The first line declares mybox as a reference to an object of type Box. After this line executes,
mybox contains the value null, which indicates that it does not yet point to an actual object. Any
attempt to use mybox at this point will result in a compile-time error. The next line allocates an
2
actual object and assigns a reference to it to mybox. After the second line executes, you can use
mybox as if it were a Box object. But in reality, mybox simply holds the memory address of the
actual Box object.
It is important to understand that new allocates memory for an object during run time.
Assigning object Reference variables
mybox will be an instance of Box. each time you create an instance of a class, you are creating
an object that contains its own copy of each instance variable defined by the class. Thus, every
Box object will contain its own copies of the instance variables width, height, and depth. To
access these variables, you will use the dot (.) operator. The dot operator links the name of the
object with the name of an instance variable. For example, to assign the width variable of
mybox the value 100, you would use the following statement:
mybox.width = 100;
What do you think the following fragment does?
Box b1 = new Box();
Box b2 = b1;
3
Although b1 and b2 both refer to the same object, they are not linked in any other way. For
example, a subsequent assignment to b1 will simply unhook b1 from the original object without
affecting the object or affecting b2. For example:
Box b1 = new Box();
Box b2 = b1;
// ...
b1 = null;
Here, b1 has been set to null, but b2 still points to the original object.
Introducing Methods
As mentioned at the beginning of this chapter, classes usually consist of two things: instance
variables and methods. The topic of methods is a large one because Java gives them so much
power and flexibility. In fact, much of the next chapter is devoted to methods. However, there
are some fundamentals that you need to learn now so that you can begin to add methods to your
classes.
This is the general form of a method:
type name(parameter-list) {
// body of method
}
Here, type specifies the type of data returned by the method. This can be any valid type,
including class types that you create. 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.
4
What are Constructors?
A constructor initializes an object immediately upon creation. It has the same name as the class
in which it resides and is syntactically similar to a method.
Once defined, the constructor is automatically called immediately after the object is 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. It is the
constructor's job to initialize the internal state of an object so that the code creating an instance
will have a fully initialized, usable object immediately.
What are the Characteristics of constructors?
An interface cannot have the constructor.
Constructors cannot be private.
A constructor cannot be abstract, static, final, native, strictfp, or synchronized
A constructor can be overloaded.
Constructors cannot return a value.
Constructors do not have a return type; not even void.
An abstract class can have the constructor.
Constructors name must be similar to that of the class name inside which it resides.
Constructors are automatically called when an object is created.
Understanding Types of Constructors
There are two types of constructors:
Default constructor (no-arg constructor)
Parameterized constructor
Default Constructor
A constructor having no parameter is known as default constructor and no-arg constructor.
5
Example
class ConEx {
int num;
String name;
ConEx () { System.out.println("Constructor called"); }
}
class GFG {
public static void main(String[] args)
{
ConEx geek1 = new ConEx ();
// Default constructor provides the default
// values to the object like 0, null
System.out.println(geek1.name);
System.out.println(geek1.num);
}
}
Output:
Constructor called
null
0
Parameterized constructor
class ParamCons {
// data members of the class.
String name;
int id;
6
ParamCons (String name, int id)
{
this.name = name;
this.id = id;
}
}
class GFG {
public static void main(String[] args)
{
ParamCons geek1 = new ParamCons ("sivam", 600426);
System.out.println("Param_Cons Name:" + geek1.name
+ " and ParamCons ID:" + geek1.id);
}
}
Output:
Param_Cons Name :sivam ParamCons ID:600426
Using this Keyword
Sometimes a method will need to refer to the object that invoked it. To allow this, Java defines
the this keyword. this can be used inside any method to refer to the current object. That is, this
is always a reference to the object on which the method was invoked. You can use this anywhere
a reference to an object of the current class' type is permitted.
// A redundant use of this.
Box(double w, double h, double d) {
this.width = w;
this.height = h;
this.depth = d;
}
Introduction to Garbage Collection
7
Garbage collection in Java is the process by which Java programs perform automatic memory
management. Java programs compile to bytecode that can be run on a Java Virtual Machine, or
JVM for short. When Java programs run on the JVM, objects are created on the heap, which is
a portion of memory dedicated to the program.
Concepts Related to Garbage Collection in Java
1. Unreachable objects: An object is said to be unreachable if it doesn’t contain any reference
to it. Also, note that objects which are part of the island of isolation are also unreachable.
Integer i = new Integer(4);
// the new Integer object is reachable via the reference in 'i'
i = null;
// the Integer object is no longer reachable.
2. Eligibility for garbage collection: An object is said to be eligible for GC(garbage
collection) if it is unreachable. After i = null, integer object 4 in the heap area is suitable for
garbage collection in the above image.
8
Ways to make an object eligible for Garbage Collector
Even though the programmer is not responsible for destroying useless objects but it is
highly recommended to make an object unreachable(thus eligible for GC) if it is no longer
required. There are generally four ways to make an object eligible for garbage collection.
1. Nullifying the reference variable
2. Re-assigning the reference variable
3. An object created inside the method
4. Island of Isolation
Ways for requesting JVM to run Garbage Collector
Once we make an object eligible for garbage collection, it may not destroy immediately by
the garbage collector. Whenever JVM runs the Garbage Collector program, then only the
object will be destroyed. But when JVM runs Garbage Collector, we can not expect. We
can also request JVM to run Garbage Collector. There are two ways to do it :
1. Using System.gc() method: System class contain static method gc() for requesting
JVM to run Garbage Collector.
2. Using Runtime.getRuntime().gc() method: Runtime class allows the application to
interface with the JVM in which the application is running. Hence by using its gc()
method, we can request JVM to run Garbage Collector.
3. There is no guarantee that any of the above two methods will run Garbage Collector.
4. The call System.gc() is effectively equivalent to the call : Runtime.getRuntime().gc()
Using Finalize() method
Just before destroying an object, Garbage Collector calls finalize() method on the object to
perform cleanup activities. Once finalize() method completes, Garbage Collector destroys
that object. finalize() method is present in Object class with the following prototype.
protected void finalize() throws Throwable
9
Based on our requirement, we can override finalize() method for performing our cleanup
activities like closing connection from the database.
1. The finalize() method is called by Garbage Collector, not JVM. However, Garbage
Collector is one of the modules of JVM.
2. Object class finalize() method has an empty implementation. Thus, it is recommended to
override the finalize() method to dispose of system resources or perform other cleanups.
3. The finalize() method is never invoked more than once for any object.
4. If an uncaught exception is thrown by the finalize() method, the exception is ignored, and
the finalization of that object terminates.
Overloading methods
In Java it is possible to define two or more methods within the same class that share the same
name, as long as their parameter declarations are different. When this is the case, the methods are
said to be overloaded, and the process is referred to as method overloading. Method overloading
is one of the ways that Java implements polymorphism.
class OverloadDemo
{
void test()
{
System.out.println("No parameters");
}
// Overload test for one integer parameter.
void test(int a) {
System.out.println("a: " + a);
}
// Overload test for two integer parameters.
void test(int a, int b) {
System.out.println("a and b: " + a + " " + b);
}
// overload test for a double parameter
double test(double a) {
10
System.out.println("double a: " + a);
return a*a;
}
}
class Overload
{
public static void main(String args[])
{
OverloadDemo ob = new OverloadDemo();
double result;
// call all versions of test()
ob.test();
ob.test(10);
ob.test(10, 20);
result = ob.test(123.2);
System.out.println("Result of ob.test(123.2): " + result);
}
}
output:
No parameters
a: 10
a and b: 10 20
double a: 123.2
Result of ob.test(123.2): 15178.24
Overloading constructors
In addition to overloading normal methods, you can also overload constructor methods. In fact,
for most real-world classes that you create, overloaded constructors will be the norm, not the
exception. To understand why, let's return to the Box class developed in the preceding chapter.
Following is the latest version of Box:
11
class Box {
double width;
double height;
double depth;
// constructor used when all dimensions specified
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
// constructor used when no dimensions specified
Box() {
width = -1; // use -1 to indicate
height = -1; // an uninitialized
depth = -1; // box
}
// constructor used when cube is created
Box(double len) {
width = height = depth = len;
}
// compute and return volume
double volume() {
return width * height * depth;
}
}
class OverloadCons {
public static void main(String args[]) {
// create boxes using the various constructors
Box mybox1 = new Box(10, 20, 15);
Box mybox2 = new Box();
Box mycube = new Box(7);
double vol;
12
// get volume of first box
vol = mybox1.volume();
System.out.println("Volume of mybox1 is " + vol);
// get volume of second box
vol = mybox2.volume();
System.out.println("Volume of mybox2 is " + vol);
// get volume of cube
vol = mycube.volume();
System.out.println("Volume of mycube is " + vol);
}
}
Output
Volume of mybox1 is 3000.0
Volume of mybox2 is -1.0
Volume of mycube is 343.0
Using objects as parameters
So far we have only been using simple types as parameters to methods. However, it is both
correct and common to pass objects to methods. For example, consider the following simple
program:
class Test
{
int a, b;
Test(int i, int j) {
a = i;
b = j;
}
// return true if o is equal to the invoking object
boolean equals(Test o) {
13
if(o.a == a && o.b == b) return true;
else return false;
}
}
class PassOb {
public static void main(String args[]) {
Test ob1 = new Test(100, 22);
Test ob2 = new Test(100, 22);
Test ob3 = new Test(-1, -1);
System.out.println("ob1 == ob2: " + ob1.equals(ob2));
System.out.println("ob1 == ob3: " + ob1.equals(ob3));
}
}
This program generates the following output:
ob1 == ob2: true
ob1 == ob3: false
Argument Passing
In general, there are two ways that a computer language can pass an argument to a subroutine.
The first way is call-by-value. This method copies the value of an argument into the formal
parameter of the subroutine. Therefore, changes made to the parameter of the subroutine have no
effect on the argument used to call it. The second way an argument can be passed is call-by-
reference. In this method, a reference to an argument (not the value of the argument) is passed to
the parameter. Inside the subroutine, this reference is used to access the actual argument
specified in the call. This means that changes made to the parameter will affect the argument
used to call the subroutine. As you will see, Java uses both methods, depending upon what is
passed. In Java, when you pass a simple type to a method, it is passed by value. Thus, what
occurs to the parameter that receives the argument has no effect outside the method. For
example, consider the following program:
class Test {
void meth(int i, int j) {
14
i *= 2;
j /= 2;
}
}
class CallByValue {
public static void main(String args[]) {
Test ob = new Test();
int a = 15, b = 20;
System.out.println("a and b before call: " +
a + " " + b);
ob.meth(a, b);
System.out.println("a and b after call: " +
a + " " + b);
}
}
The output from this program is shown here:
a and b before call: 15 20
a and b after call: 15 20
Returning Objects
A method can return any type of data, including class types that you create. For example,
in the following program, the incrByTen( ) method returns an object in which the value of
a is ten greater than it is in the invoking object.
class Test {
int a;
Test(int i) {
a = i;
}
Test incrByTen() {
Test temp = new Test(a+10);
return temp;
15
}
}
class RetOb {
public static void main(String args[]) {
Test ob1 = new Test(2);
Test ob2;
ob2 = ob1.incrByTen();
System.out.println("ob1.a: " + ob1.a);
System.out.println("ob2.a: " + ob2.a);
ob2 = ob2.incrByTen();
System.out.println("ob2.a after second increase: "
+ ob2.a);
}
}
output
ob1.a: 2
ob2.a: 12
ob2.a after second increase: 22
Recursion
Java supports recursion. Recursion is the process of defining something in terms of itself.
As it relates to Java programming, recursion is the attribute that allows a method to call
itself. A method that calls itself is said to be recursive.
// A simple example of recursion.
class Factorial {
// this is a recursive function
int fact(int n) {
int result;
if(n==1) return 1;
result = fact(n-1) * n;
return result;
}
}
16
class Recursion {
public static void main(String args[]) {
Factorial f = new Factorial();
System.out.println("Factorial of 3 is " + f.fact(3));
System.out.println("Factorial of 4 is " + f.fact(4));
System.out.println("Factorial of 5 is " + f.fact(5));
}
}
Output
Factorial of 3 is 6
Factorial of 4 is 24
Factorial of 5 is 120
Introducing Access Control
Java's access specifiers are public, private, and protected. Java also defines a default access
level. protected applies only when inheritance is involved. The other access specifiers are
described next.
Let's begin by defining public and private. When a member of a class is modified by the public
specifier, then that member can be accessed by any other code in your program. When a member
of a class is specified as private, then that member can only be accessed by other members of its
class. Now you can understand why main( ) has always been preceded by the public specifier. It
is called by code that is outside the program—that is, by the Java run-time system. When no
access specifier is used, then by default the member of a class is public within its own package,
but cannot be accessed outside of its package.
/* This program demonstrates the difference between public and private. */
class Test {
int a; // default access
public int b; // public access
private int c; // private access
// methods to access c
void setc(int i) { // set c's value
c = i;
}
17
int getc() { // get c's value
return c;
}
}
class AccessTest {
public static void main(String args[]) {
Test ob = new Test();
// These are OK, a and b may be accessed directly
ob.a = 10;
ob.b = 20;
// This is not OK and will cause an error
// ob.c = 100; // Error!
// You must access c through its methods
ob.setc(100); // OK
System.out.println("a, b, and c: " + ob.a + " " +
ob.b + " " + ob.getc());
}
}
As you can see, inside the Test class, a uses default access, which for this example is
the same as specifying public. b is explicitly specified as public. Member c is given
private access. This means that it cannot be accessed by code outside of its class. So,
inside the AccessTest class, c cannot be used directly. It must be accessed through its
public methods: setc( ) and getc( ). If you were to remove the comment symbol from the
beginning of the following line,
// ob.c = 100; // Error!
Understanding Static variables and methods
There will be times when you will want to define a class member that will be used
independently of any object of that class. Normally a class member must be accessed
only in conjunction with an object of its class. However, it is possible to create a member
that can be used by itself, without reference to a specific instance. To create such a
18
member, precede its declaration with the keyword static. When a member is declared
static, it can be accessed before any objects of its class are created, and without
reference to any object. You can declare both methods and variables to be static. The
most common example of a static member is main( ). main( ) is declared as static
because it must be called before any objects exist.
Instance variables declared as static are, essentially, global variables. When objects of
its class are declared, no copy of a static variable is made. Instead, all instances of the
class share the same static variable.
Methods declared as static have several restrictions:
• They can only call other static methods.
• They must only access static data.
• They cannot refer to this or super in any way.
class UseStatic {
static int a = 3;
static int b;
static void meth(int x) {
System.out.println("x = " + x);
System.out.println("a = " + a);
System.out.println("b = " + b);
}
static {
System.out.println("Static block initialized.");
b = a * 4;
}
public static void main(String args[]) {
meth(42);
}
}
Understanding Final variables and methods
19
A variable can be declared as final. Doing so prevents its contents from being modified.
This means that you must initialize a final variable when it is declared. (In this usage,
final is similar to const in C/C++.) For example:
final int FILE_NEW = 1;
final int FILE_OPEN = 2;
final int FILE_SAVE = 3;
final int FILE_SAVEAS = 4;
final int FILE_QUIT = 5;
Subsequent parts of your program can now use FILE_OPEN, etc., as if they were
constants, without fear that a value has been changed.
It is a common coding convention to choose all uppercase identifiers for final variables.
Variables declared as final do not occupy memory on a per-instance basis. Thus, a final
variable is essentially a constant.
The keyword final can also be applied to methods, but its meaning is substantially different
than when it is applied to variables.
Working with Nested Class and Inner Class
It is possible to define a class within another class; such classes are known as nested
classes. The scope of a nested class is bounded by the scope of its enclosing class.
Thus, if class B is defined within class A, then B is known to A, but not outside of 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.
There are two types of nested classes: static and non-static. A static nested class is one
which has the static modifier applied. Because it is static, it must access the members of
its enclosing class through an object. That is, it cannot refer to members of its enclosing
class directly. Because of this restriction, static nested classes are seldom used.
The most important type of nested class is the inner class. An inner class is a non-static
nested class. It has access to all of the variables and methods of its outer class and may
refer to them directly in the same way that other non-static members of the outer class
20
do. Thus, an inner class is fully within the scope of its enclosing class.
The following program illustrates how to define and use an inner class. The class named
Outer has one instance variable named outer_x, one instance method named test( ),
and defines one inner class called Inner.
// Demonstrate an inner class.
class Outer {
int outer_x = 100;
void test() {
Inner inner = new Inner();
inner.display();
}
// this is an inner class
class Inner {
void display() {
System.out.println("display: outer_x = " + outer_x);
}
}
}
class InnerClassDemo {
public static void main(String args[]) {
Outer outer = new Outer();
outer.test();
}
}
Output from this application is shown here:
display: outer_x = 100
Introduction to String Class
String is probably the most commonly used class in Java's class library. The obvious reason for
this is that strings are a very important part of programming. The first thing to understand about
21
strings is that every string you create is actually an object of type String. Even string constants
are actually String objects. For example, in the statement
System.out.println("This is a String, too");
the string "This is a String, too" is a String constant. Fortunately, Java handles String
constants in the same way that other computer languages handle "normal" strings, so
you don't have to worry about this.
The second thing to understand about strings is that objects of type String are
immutable; once a String object is created, its contents cannot be altered. While this may
seem like a serious restriction, it is not, for two reasons:
• If you need to change a string, you can always create a new one that contains the
modifications.
• Java defines a peer class of String, called StringBuffer, which allows strings to be
altered, so all of the normal string manipulations are still available in Java.
Strings can be constructed a variety of ways. The easiest is to use a statement like this:
String myString = "this is a test";
Once you have created a String object, you can use it anywhere that a string is allowed.
For example, this statement displays myString:
System.out.println(myString);
Java defines one operator for String objects: +. It is used to concatenate two strings. For
example, this statement
String myString = "I" + " like " + "Java.";
results in myString containing "I like Java."
// Demonstrating Strings.
class StringDemo {
public static void main(String args[]) {
String strOb1 = "First String";
22
String strOb2 = "Second String";
String strOb3 = strOb1 + " and " + strOb2;
System.out.println(strOb1);
System.out.println(strOb2);
System.out.println(strOb3);
}
}
The output produced by this program is shown here:
First String
Second String
First String and Second String
The String class contains several methods that you can use. Here are a few. You can
test two strings for equality by using equals( ). You can obtain the length of a string by
calling the length( ) method. You can obtain the character at a specified index within a
string by calling charAt( ). The general forms of these three methods are shown here:
boolean equals(String object)
int length( )
char charAt(int index)
Here is a program that demonstrates these methods:
// Demonstrating some String methods.
class StringDemo2 {
public static void main(String args[]) {
String strOb1 = "First String";
String strOb2 = "Second String";
String strOb3 = strOb1;
System.out.println("Length of strOb1: " +
strOb1.length());
System.out.println("Char at index 3 in strOb1: " +
strOb1.charAt(3));
if(strOb1.equals(strOb2))
System.out.println("strOb1 == strOb2");
23
else
System.out.println("strOb1 != strOb2");
if(strOb1.equals(strOb3))
System.out.println("strOb1 == strOb3");
else
System.out.println("strOb1 != strOb3");
}
}
This program generates the following output:
Length of strOb1: 12
Char at index 3 in strOb1: s
strOb1 != strOb2
strOb1 == strOb3
Of course, you can have arrays of strings, just like you can have arrays of any other type
of object. For example:
// Demonstrate String arrays.
class StringDemo3 {
public static void main(String args[]) {
String str[] = { "one", "two", "three" };
for(int i=0; i<str.length; i++)
System.out.println("str[" + i + "]: " +
str[i]);
}
}
Here is the output from this program:
str[0]: one
str[1]: two
str[2]: three
Command Line arguments
Sometimes you will want to pass information into a program when you run it. This is
accomplished by passing command-line arguments to main( ). A command-line
24
argument is the information that directly follows the program's name on the command line
when it is executed. To access the command-line arguments inside a Java program is
quite easy—they are stored as strings in the String array passed to main( ).
class CommandLine {
public static void main(String args[]) {
for(int i=0; i<args.length; i++)
System.out.println("args[" + i + "]: " +
args[i]);
}
}
Try executing this program, as shown here:
java CommandLine this is a test 100 -1
When you do, you will see the following output:
args[0]: this
args[1]: is
args[2]: a
args[3]: test
args[4]: 100
args[5]: -1
25