Java Tutorial
Java Tutorial
Java Tutorial
1. Java - What, Where and Why?
2. What is Java
3. Where Java is used
4. Java Applications
Java Tutorial or Core Java Tutorial is a widely used robust technology. Let's start learning of
java from basic questions like what is java tutorial, core java, where it is used, what type of
applications are created in java and why use java.
What is Java?
Java is a programming language and a platform.
Platform Any hardware or software environment in which a program runs, known as a
platform. Since Java has its own Runtime Environment (JRE) and API, it is called platform.
Java Example
1. class Simple{
2.
public static void main(String args[]){
3.
System.out.println("Hello Java");
4.
}
5. }
Test it Now
Where it is used?
According to Sun, 3 billion devices run java. There are many devices where java is currently
used. Some of them are as follows:
1.
2.
3.
4.
5.
6.
2
7. Robotics
8. Games etc.
1) Standalone Application
It is also known as desktop application or window-based application. An application that we
need to install on every machine such as media player, antivirus etc. AWT and Swing are
used in java for creating standalone applications.
2) Web Application
An application that runs on the server side and creates dynamic page, is called web
application. Currently, servlet, jsp, struts, jsf etc. technologies are used for creating web
applications in java.
3) Enterprise Application
An application that is distributed in nature, such as banking applications etc. It has the
advantage of high level security, load balancing and clustering. In java, EJB is used for
creating enterprise applications.
4) Mobile Application
An application that is created for mobile devices. Currently Android and Java ME are used
for creating mobile applications.
JVM
JVM (Java Virtual Machine) is an abstract machine. It is a specification that provides
runtime environment in which java bytecode can be executed.
JVMs are available for many hardware and software platforms. JVM, JRE and JDK are
platform dependent because configuration of each OS differs. But, Java is platform
independent.
The JVM performs following main tasks:
Loads code
Verifies code
Executes code
Provides runtime environment
JRE
JRE is an acronym for Java Runtime Environment.It is used to provide runtime
environment.It is the implementation of JVM.It physically exists.It contains set of
libraries + other files that JVM uses at runtime.
Implementation of JVMs are also actively released by other companies besides Sun
Micro Systems.
JDK
JDK is an acronym for Java Development Kit.It physically exists.It contains JRE +
development tools.
What is JVM?
It is:
6
1. A specification where working of Java Virtual Machine is specified. But
implementation provider is independent to choose the algorithm. Its implementation
has been provided by Sun and other companies.
2. An implementation Its implementation is known as JRE (Java Runtime
Environment).
3. Runtime Instance Whenever you write java command on the command prompt to
run the java class, and instance of JVM is created.
What it does?
The JVM performs following operation:
Loads code
Verifies code
Executes code
Provides runtime environment
Memory area
Class file format
Register set
Garbage-collected heap
Fatal error reporting etc.
1) Classloader:
Classloader is a subsystem of JVM that is used to load class files.
2) Class(Method) Area:
Class(Method) Area stores per-class structures such as the runtime constant pool, field and
method data, the code for methods.
3) Heap:
It is the runtime data area in which objects are allocated.
4) Stack:
Java Stack stores frames.It holds local variables and partial results, and plays a part in
method invocation and return.
Each thread has a private JVM stack, created at the same time as thread.
A new frame is created each time a method is invoked. A frame is destroyed when its
method invocation completes.
7) Execution Engine:
It contains:
1) A virtual processor
2) Interpreter:Read bytecode stream then execute the instructions.
3) Just-In-Time(JIT) compiler:It is used to improve the performance.JIT compiles
parts of the byte code that have similar functionality at the same time, and hence
reduces the amount of time needed for compilation.Here the term ?compiler? refers to a
translator from the instruction set of a Java virtual machine (JVM) to the instruction set
of a specific CPU.
memory location. There are three types of variables: local, instance and static. There are
two types of datatypes in java, primitive and non-primitive.
Variable
Variable is name of reserved area allocated in memory.
Types of Variable
There are three types of variables in java
local variable
instance variable
static variable
10
Local Variable
A variable that is declared inside the method is called local variable.
Instance Variable
A variable that is declared inside the class but outside the method is called instance
variable . It is not declared as static.
Static variable
A variable that is declared as static is called static variable. It cannot be local.
void method(){
11
}//end of class
12
boolean
false
1 bit
char
'\u0000'
2 byte
byte
1 byte
short
2 byte
int
4 byte
long
0L
8 byte
float
0.0f
4 byte
double
0.0d
8 byte
Unicode System
Unicode is a universal international standard character encoding that is capable of
representing most of the world's written languages.
ASCII (American Standard Code for Information Interchange) for the United
States.
ISO 8859-1 for Western European Language.
KOI-8 for Russian.
GB18030 and BIG-5 for chinese, and so on.
13
common characters are encoded as single bytes, other require two or more byte.
To solve these problems, a new language standard was developed i.e. Unicode System.
In unicode, character holds 2 byte, so java also uses 2 byte for characters.
lowest value:\u0000
highest value:\uFFFF
Operators in java
Operator is a special symbol that is used to perform operations. There are many types of
operators in java such as unary operator, arithmetic operator, relational operator, shift
operator, bitwise operator, ternary operator and assignment operator.
Precedence of Operators
Operators
Precedence
postfix
expr++ expr--
unary
multiplicative
* / %
additive
+ -
shift
relational
equality
== !=
14
bitwise AND
&
bitwise exclusive OR
bitwise inclusive OR
logical AND
&&
logical OR
||
ternary
? :
assignment
Useful Programs:
There is given some useful programs such as factorial number, prime number, fibonacci
series etc.
It is better for the freshers to skip this topic and come to it after OOPs
concepts.
15
}
}
16
d=n;
while(n>0)
{
a=n%10;
n=n/10;
c=c+(a*a*a);
}
if(d==c)
System.out.println("armstrong number");
else
System.out.println("it is not an armstrong number");
}
}
n=a,b=a,rev=0;
while(n>0)
{
a=n%10;
rev=rev*10+a;
n=n/10;
}
if(rev==b)
System.out.println("it is Palindrome");
17
else
System.out.println("it is not palinedrome");
}
}
System.out.println("a= "+a);
System.out.println("b= "+b);
}
}
return n*=fact(n-1);
}
18
int f=fact(5);
System.out.println(f);
}
}
19
Object
Class
Inheritance
Polymorphism
Abstraction
Encapsulation
Object
Any entity that has state and behavior is known as an object. For example: chair, pen,
table, keyboard, bike etc. It can be physical and logical.
Class
Collection of objects is called class. It is a logical entity.
Inheritance
20
When one object acquires all the properties and behaviours of parent object i.e.
known as inheritance. It provides code reusability. It is used to achieve runtime
polymorphism.
Polymorphism
When one task is performed by different ways i.e. known as polymorphism. For
example: to convense the customer differently, to draw something e.g. shape or rectangle
etc.
In java, we use method overloading and method overriding to achieve polymorphism.
Another example can be to speak something e.g. cat speaks meaw, dog barks woof etc.
Abstraction
Hiding internal details and showing functionality is known as abstraction. For
example: phone call, we don't know the internal processing.
In java, we use abstract class and interface to achieve abstraction.
21
Encapsulation
Binding (or wrapping) code and data together into a single unit is known as
encapsulation. For example: capsule, it is wrapped with different medicines.
A java class is the example of encapsulation. Java bean is the fully encapsulated class
because all the data members are private here.
22
Name
class name
Convention
should start with uppercase letter and be a noun e.g. String, Color, Button,
System, Thread etc.
interface
should start with uppercase letter and be an adjective e.g. Runnable, Remote,
name
ActionListener etc.
method name
should start with lowercase letter and be a verb e.g. actionPerformed(), main(),
print(), println() etc.
variable name
package
name
constants
name
23
If name is combined with two words, second word will start with uppercase letter always
e.g. actionPerformed(), firstName, ActionEvent, ActionListener etc.
Object in Java
An entity that has state and behavior is known as an object e.g. chair, bike, marker, pen,
table, car etc. It can be physical or logical (tengible and intengible). The example of
integible object is banking system.
24
For Example: Pen is an object. Its name is Reynolds, color is white etc. known as its
state. It is used to write, so writing is its behavior.
Object is an instance of a class. Class is a template or blueprint from which objects
are created. So object is the instance(result) of a class.
Class in Java
A class is a group of objects that has common properties. It is a template or blueprint
from which objects are created.
data member
method
constructor
block
class and interface
25
2. int id;//data member (also instance variable)
3. String name;//data member(also instance variable)
4.
5. public static void main(String args[]){
6.
Student1 s1=new Student1();//creating an object of Student
7.
System.out.println(s1.id);
8.
System.out.println(s1.name);
9. }
10. }
Test it Now
Output:0 null
Method in Java
In java, a method is like function i.e. used to expose behaviour of an object.
Advantage of Method
Code Reusability
Code Optimization
new keyword
The new keyword is used to allocate memory at runtime.
26
4.
5. void insertRecord(int r, String n){ //method
6.
rollno=r;
7.
name=n;
8. }
9.
10. void displayInformation(){System.out.println(rollno+" "+name);}//method
11.
12. public static void main(String args[]){
13. Student2 s1=new Student2();
14. Student2 s2=new Student2();
15.
16. s1.insertRecord(111,"Karan");
17. s2.insertRecord(222,"Aryan");
18.
19. s1.displayInformation();
20. s2.displayInformation();
21.
22. }
23. }
Test it Now
Output:111 Karan
222 Aryan
27
As you see in the above figure, object gets the memory in Heap area and reference
variable refers to the object allocated in the Heap memory area. Here, s1 and s2 both
are reference variables that refer to the objects allocated in memory.
28
15.
16. r1.insert(11,5);
17. r2.insert(3,15);
18.
19. r1.calculateArea();
20. r2.calculateArea();
21. }
22. }
Output:55
45
By
By
By
By
new keyword
newInstance() method
clone() method
factory method etc.
Annonymous object
Annonymous simply means nameless.An object that have no reference is known as
annonymous object.
If you have to use an object only once, annonymous object is a good approach.
1. class Calculation{
2.
3. void fact(int n){
4.
int fact=1;
5.
for(int i=1;i<=n;i++){
6.
fact=fact*i;
7.
}
8. System.out.println("factorial is "+fact);
9. }
10.
11. public static void main(String args[]){
12. new Calculation().fact(5);//calling method with annonymous object
13. }
14. }
Output:Factorial is 120
29
30
Suppose you have to perform addition of the given numbers but there can be any number
of arguments, if you write the method such as a(int,int) for two parameters, and
b(int,int,int) for three parameters then it may be difficult for you as well as other
programmers to understand the behaviour of the method because its name differs. So, we
perform method overloading to figure out the program quickly.
In java, Methood Overloading is not possible by changing the return type of the
method.
31
2.
void sum(int a,int b){System.out.println(a+b);}
3.
void sum(int a,int b,int c){System.out.println(a+b+c);}
4.
5.
public static void main(String args[]){
6.
Calculation obj=new Calculation();
7.
obj.sum(10,10,10);
8.
obj.sum(20,20);
9.
10. }
11. }
Test it Now
Output:30
40
Que) Why Method Overloaing is not possible by changing the return type of method?
In java, method overloading is not possible by changing the return type of the method
because there may occur ambiguity. Let's see how ambiguity may occur:
32
33
As displayed in the above diagram, byte can be promoted to short, int, long, float or double.
The short datatype can be promoted to int,long,float or double. The char datatype can be
promoted to int,long,float or double and so on.
34
60
Constructor in Java
1. Types of constructors
35
1. Default Constructor
2. Parameterized Constructor
2. Constructor Overloading
3. Does constructor return any value
4. Copying the values of one object into another
5. Does constructor perform other task instead initialization
Constructor is a special type of method that is used to initialize the object.
Constructor is invoked at the time of object creation. It constructs the values i.e.
provides data for the object that is why it is known as constructor.
Types of constructors
There are two types of constructors:
1. default constructor (no-arg constructor)
2. parameterized constructor
36
1) Default Constructor
A constructor that have no parameter is known as default constructor.
class Bike1{
Bike(){System.out.println("Bike is created");}
public static void main(String args[]){
Bike1 b=new Bike1();
}
}
Test it Now
Output: Bike is created
37
Parameterized constructor
A constructor that have parameters is known as parameterized constructor.
38
Constructor Overloading
Constructor overloading is a technique in Java in which a class can have any number of
constructors that differ in parameter lists.The compiler differentiates these constructors
by taking into account the number of parameters in the list and their type.
39
9.
Student5(int i,String n,int a){
10.
id = i;
11.
name = n;
12.
age=a;
13.
}
14.
void display(){System.out.println(id+" "+name+" "+age);}
15.
16.
public static void main(String args[]){
17.
Student5 s1 = new Student5(111,"Karan");
18.
Student5 s2 = new Student5(222,"Aryan",25);
19.
s1.display();
20.
s2.display();
21. }
22. }
Test it Now
Output:111 Karan 0
222 Aryan 25
Constructor
Constructor is used to initialize the state of an object.
Method
Method is used to expose behaviour of
an object.
any case.
40
By constructor
By assigning the values of one object into another
By clone() method of Object class
In this example, we are going to copy the values of one object into another using
constructor.
1. class Student6{
2.
int id;
3.
String name;
4.
Student6(int i,String n){
5.
id = i;
6.
name = n;
7.
}
8.
9.
Student6(Student s){
10.
id = s.id;
11.
name =s.name;
12.
}
13.
void display(){System.out.println(id+" "+name);}
14.
15.
public static void main(String args[]){
16.
Student6 s1 = new Student6(111,"Karan");
17.
Student6 s2 = new Student6(s1);
18.
s1.display();
19.
s2.display();
20. }
21. }
Test it Now
Output:111 Karan
111 Karan
41
5.
id = i;
6.
name = n;
7.
}
8.
Student7(){}
9.
void display(){System.out.println(id+" "+name);}
10.
11.
public static void main(String args[]){
12.
Student7 s1 = new Student7(111,"Karan");
13.
Student7 s2 = new Student7();
14.
s2.id=s1.id;
15.
s2.name=s1.name;
16.
s1.display();
17.
s2.display();
18. }
19. }
Test it Now
Output:111 Karan
111 Karan
static keyword
1. Static variable
2. Program of counter without static variable
3. Program of counter with static variable
4. Static method
5. Restrictions for static method
6. Why main method is static ?
7. Static block
8. Can we execute a program without main method ?
42
The static keyword is used in java mainly for memory management. We may apply static
keyword with variables, methods, blocks and nested class. The static keyword belongs to
the class than instance of the class.
The static can be:
1.
2.
3.
4.
1) static variable
If you declare any variable as static, it is known static variable.
The static variable can be used to refer the common property of all objects (that is
not unique for each object) e.g. company name of employees,college name of
students etc.
The static variable gets memory only once in class area at the time of class loading.
43
2.
3. class Student8{
4.
int rollno;
5.
String name;
6.
static String college ="ITS";
7.
8.
Student8(int r,String n){
9.
rollno = r;
10. name = n;
11. }
12. void display (){System.out.println(rollno+" "+name+" "+college);}
13.
14. public static void main(String args[]){
15. Student8 s1 = new Student8(111,"Karan");
16. Student8 s2 = new Student8(222,"Aryan");
17.
18. s1.display();
19. s2.display();
20. }
21. }
Test it Now
Output:111 Karan ITS
222 Aryan ITS
44
45
12. Counter2 c2=new Counter2();
13. Counter2 c3=new Counter2();
14.
15. }
16. }
Test it Now
Output:1
2
3
2) static method
If you apply static keyword with any method, it is known as static method
46
29.
}
30. }
Test it Now
Output:111 Karan BBDIT
222 Aryan BBDIT
333 Sonoo BBDIT
47
3)static block
48
this keyword
1. this keyword
2. Usage of this keyword
1. to refer the current class instance variable
2. to invoke the current class constructor
3. to invoke the current class method
4. to pass as an argument in the method call
5. to pass as an argument in the constructor call
6. to return the current class instance
3. Proving this keyword
There can be a lot of usage of this keyword. In java, this is a reference variablethat
refers to the current object.
Suggestion:If you are beginner to java, lookup only two usage of this keyword.
49
50
9.
}
10.
void display(){System.out.println(id+" "+name);}
11.
public static void main(String args[]){
12.
Student11 s1 = new Student11(111,"Karan");
13.
Student11 s2 = new Student11(222,"Aryan");
14.
s1.display();
15.
s2.display();
16. }
17. }
Test it Now
Output111 Karan
222 Aryan
If local variables(formal arguments) and instance variables are different, there is no need
to use this keyword like in the following program:
51
7.
name = n;
8.
}
9.
void display(){System.out.println(id+" "+name);}
10.
public static void main(String args[]){
11.
Student12 e1 = new Student12(111,"karan");
12.
Student12 e2 = new Student12(222,"Aryan");
13.
e1.display();
14.
e2.display();
15. }
16. }
Test it Now
Output:111 Karan
222 Aryan
52
111 Karan
222 Aryan
53
12.
13.
public static void main(String args[]){
14.
Student15 e1 = new Student15(111,"karan");
15.
Student15 e2 = new Student15(222,"Aryan");
16.
e1.display();
17.
e2.display();
18. }
19. }
Test it Now
Output:Compile Time Error
1. class S{
2.
void m(){
3.
System.out.println("method is invoked");
4.
}
5.
void n(){
6.
this.m();//no need because compiler does it for you.
7.
}
8.
void p(){
9.
n();//complier will add this to invoke n() method as this.n()
10. }
11. public static void main(String args[]){
12. S s1 = new S();
54
13. s1.p();
14. }
15. }
Test it Now
Output:method is invoked
55
8.
}
9. }
10.
11. class A4{
12. int data=10;
13. A4(){
14. B b=new B(this);
15. b.display();
16. }
17. public static void main(String args[]){
18. A4 a=new A4();
19. }
20. }
Test it Now
Output:10
56
Inheritance in Java
1. Inheritance
2. Types of Inheritance
3. Why multiple inheritance is not possible in java in case of class?
Inheritance in java is a mechanism in which one object acquires all the properties and
behaviors of parent object.
The idea behind inheritance in java is that you can create new classes that are built upon
existing classes. When you inherit from an existing class, you can reuse methods and fields
of parent class, and you can add new methods and fields also.
Inheritance represents the IS-A relationship, also known as Parent-Child relationship.
Syntax of Inheritance
1. class Subclass-name extends Superclass-name
2. {
57
3.
//methods and fields
4. }
The keyword extends indicates that you are making a new class that derives from an
existing class.
In the terminology of Java, a class that is inherited is called a super class. The new class is
called a subclass.
As displayed in the above figure, Programmer is the subclass and Employee is the
superclass. Relationship between two classes isProgrammer IS-A Employee.It means
that Programmer is a type of Employee.
1. class Employee{
2. float salary=40000;
3. }
4.
5. class Programmer extends Employee{
6. int bonus=10000;
7. public static void main(String args[]){
8.
Programmer p=new Programmer();
9.
System.out.println("Programmer salary is:"+p.salary);
58
10. System.out.println("Bonus of Programmer is:"+p.bonus);
11. }
12. }
Test it Now
Programmer salary is:40000.0
Bonus of programmer is:10000
In the above example, Programmer object can access the field of own class as well as of
Employee class i.e. code reusability.
Types of Inheritance
On the basis of class, there can be three types of inheritance: single, multilevel and
hierarchical in java.
In java programming, multiple and hybrid inheritance is supported through interface only.
We will learn about interfaces later.
59
When a class extends multiple classes i.e. known as multiple inheritance. For Example:
class A{
void msg(){System.out.println("Hello");}
}
class B{
60
5. void msg(){System.out.println("Welcome");}
6. }
7. class C extends A,B{//suppose if it were
8.
9. Public Static void main(String args[]){
10. C obj=new C();
11. obj.msg();//Now which msg() method would be invoked?
12. }
13. }
Test it Now
Compile Time Error
Aggregation in Java
If a class have an entity reference, it is known as Aggregation. Aggregation represents HASA relationship.
Consider a situation, Employee object contains many informations such as id, name, emailId
etc. It contains one more object named address, which contains its own informations such
as city, state, country, zipcode etc. as given below.
1.
2.
3.
4.
5.
6.
class Employee{
int id;
String name;
Address address;//Address is a class
...
}
In such case, Employee has an entity reference address, so relationship is Employee HAS-A
address.
61
In this example, we have created the reference of Operation class in the Circle class.
1. class Operation{
2. int square(int n){
3.
return n*n;
4. }
5. }
6.
7. class Circle{
8. Operation op;//aggregation
9. double pi=3.14;
10.
11. double area(int radius){
12. op=new Operation();
13. int rsquare=op.square(radius);//code reusability (i.e. delegates the method call).
14. return pi*rsquare;
15. }
16.
17.
18.
19. public static void main(String args[]){
20. Circle c=new Circle();
21. double result=c.area(5);
22. System.out.println(result);
23. }
24. }
Test it Now
Output:78.5
Code reuse is also best achieved by aggregation when there is no is-a relationship.
Inheritance should be used only if the relationship is-a is maintained throughout the
lifetime of the objects involved; otherwise, aggregation is the best choice.
62
Address.java
1. public class Address1 {
2. String city,state,country;
3.
4. public Address1(String city, String state, String country) {
5.
this.city = city;
6.
this.state = state;
7.
this.country = country;
8. }
9.
10. }
Emp.java
1. public class Emp {
2. int id;
3. String name;
4. Address address;
5.
6. public Emp(int id, String name,Address address) {
7.
this.id = id;
8.
this.name = name;
9.
this.address=address;
10. }
11.
12. void display(){
13. System.out.println(id+" "+name);
14. System.out.println(address.city+" "+address.state+" "+address.country);
15. }
16.
17. public static void main(String[] args) {
18. Address address1=new Address("gzb","UP","india");
19. Address address2=new Address("gno","UP","india");
20.
21. Emp e=new Emp(111,"varun",address1);
22. Emp e2=new Emp(112,"arun",address2);
23.
24. e.display();
25. e2.display();
26.
63
27. }
28. }
Test it Now
Output:111 varun
gzb UP india
112 arun
gno UP india
class Vehicle{
64
2.
void run(){System.out.println("Vehicle is running");}
3.
}
4.
class Bike extends Vehicle{
5.
6.
public static void main(String args[]){
7.
Bike obj = new Bike();
8.
obj.run();
9.
}
10. }
Test it Now
Output:Vehicle is running
Problem is that I have to provide a specific implementation of run() method in subclass that
is why we use method overriding.
65
1. class Bank{
2. int getRateOfInterest(){return 0;}
3. }
4.
5. class SBI extends Bank{
6. int getRateOfInterest(){return 8;}
7. }
8.
9. class ICICI extends Bank{
10. int getRateOfInterest(){return 7;}
11. }
12. class AXIS extends Bank{
13. int getRateOfInterest(){return 9;}
14. }
15.
16. class Test2{
17. public static void main(String args[]){
18. SBI s=new SBI();
19. ICICI i=new ICICI();
20. AXIS a=new AXIS();
21. System.out.println("SBI Rate of Interest: "+s.getRateOfInterest());
22. System.out.println("ICICI Rate of Interest: "+i.getRateOfInterest());
23. System.out.println("AXIS Rate of Interest: "+a.getRateOfInterest());
24. }
25. }
Test it Now
Output:
SBI Rate of Interest: 8
ICICI Rate of Interest: 7
AXIS Rate of Interest: 9
66
Method Overloading
Method Overriding
program.
within a class.
relationship.
67
Note: If you are beginner to java, skip this topic and return to it after OOPs
concepts.
68
super keyword
The super is a reference variable that is used to refer immediate parent class object.
Whenever you create the instance of subclass, an instance of parent class is created
implicitly i.e. referred by super reference variable.
69
4.
int speed=50;
5. }
6.
7. class Bike4 extends Vehicle{
8.
int speed=100;
9.
10. void display(){
11. System.out.println(super.speed);//will print speed of Vehicle now
12. }
13. public static void main(String args[]){
14. Bike4 b=new Bike4();
15. b.display();
16.
17. }
18. }
Test it Now
Output:50
70
As we know well that default constructor is provided by compiler automatically but it also
adds super() for the first statement.If you are creating your own constructor and you
don't have either this() or super() as the first statement, compiler will provide super() as
the first statement of the constructor.
71
Output:Vehicle is created
10
In case there is no method in subclass as parent, there is no need to use super. In the
example given below message() method is invoked from Student class but Student class
does not have message() method, so you can directly call message() method.
class Person{
void message(){System.out.println("welcome");}
}
class Student17 extends Person{
void display(){
72
8. message();//will invoke parent class message() method
9. }
10.
11. public static void main(String args[]){
12. Student17 s=new Student17();
13. s.display();
14. }
15. }
Test it Now
Output:welcome
Que) What is the use of instance initializer block while we can directly
assign a value in instance data member? For example:
1. class Bike{
2.
int speed=100;
3. }
73
There are three places in java where you can perform operations:
1. method
2. constructor
3. block
74
constructor is invoked
instance initializer block invoked
constructor is invoked
In the above example, it seems that instance initializer block is firstly invoked but NO.
Instance intializer block is invoked at the time of object creation. The java compiler
copies the instance initializer block in the constructor after the first statement super().
So firstly, constructor is invoked. Let's understand it by the figure given below:
Note: The java compiler copies the code of instance initializer block in
every constructor.
75
There are mainly three rules for the instance initializer block. They are as follows:
1. The instance initializer block is created when instance of the class is created.
2. The instance initializer block is invoked after the parent class constructor is invoked
(i.e. after super() constructor call).
3. The instance initializer block comes in the order in which they appear.
76
12.
13. B3(int a){
14. super();
15. System.out.println("child class constructor invoked "+a);
16. }
17.
18. {System.out.println("instance initializer block is invoked");}
19.
20. public static void main(String args[]){
21. B3 b1=new B3();
22. B3 b2=new B3(10);
23. }
24. }
Test it Now
Output:parent class constructor invoked
instance initializer block is invoked
child class constructor invoked
parent class constructor invoked
instance initializer block is invoked
child class constructor invoked 10
77
static block only. We will have detailed learning of these. Let's first learn the basics of final
keyword.
1) final variable
If you make any variable as final, you cannot change the value of final variable(It will be
constant).
2) final method
If you make any method as final, you cannot override it.
78
3) final class
If you make any class as final, you cannot extend it.
79
6.
new Honda2().run();
7.
}
8. }
Test it Now
Output:running...
class Student{
int id;
String name;
final String PAN_CARD_NUMBER;
...
}
80
81
Upcasting
When reference variable of Parent class refers to the object of Child class, it is known as
upcasting. For example:
1. class A{}
2. class B extends A{}
1. A a=new B();//upcasting
82
3. }
4. class Splender extends Bike{
5.
void run(){System.out.println("running safely with 60km");}
6.
7.
public static void main(String args[]){
8.
Bike b = new Splender();//upcasting
9.
b.run();
10. }
11. }
Test it Now
Output:running safely with 60km.
class Bank{
int getRateOfInterest(){return 0;}
}
class SBI extends Bank{
int getRateOfInterest(){return 8;}
}
class ICICI extends Bank{
83
10. int getRateOfInterest(){return 7;}
11. }
12. class AXIS extends Bank{
13. int getRateOfInterest(){return 9;}
14. }
15.
16. class Test3{
17. public static void main(String args[]){
18. Bank b1=new SBI();
19. Bank b2=new ICICI();
20. Bank b3=new AXIS();
21. System.out.println("SBI Rate of Interest: "+b1.getRateOfInterest());
22. System.out.println("ICICI Rate of Interest: "+b2.getRateOfInterest());
23. System.out.println("AXIS Rate of Interest: "+b3.getRateOfInterest());
24. }
25. }
Test it Now
Output:
SBI Rate of Interest: 8
ICICI Rate of Interest: 7
AXIS Rate of Interest: 9
84
10. }
Test it Now
Output:90
85
11. Animal a=new BabyDog1();
12. a.eat();
13. }}
Test it Now
Output: Dog is eating
Since, BabyDog is not overriding the eat() method, so eat() method of Dog class is
invoked.
Understanding Type
Let's understand the type of instance.
86
5. }
static binding
When type of the object is determined at compiled time(by the compiler), it is known as
static binding.
If there is any private, final or static method in a class, there is static binding.
Dynamic binding
When type of the object is determined at run-time, it is known as dynamic binding.
87
6. void eat(){System.out.println("dog is eating...");}
7.
8. public static void main(String args[]){
9.
Animal a=new Dog();
10. a.eat();
11. }
12. }
Test it Now
Output:dog is eating...
In the above example object type cannot be determined by the compiler, because the
instance of Dog is also an instance of Animal.So compiler doesn't know its type, only its
base type.
Java instanceof
1. java instanceof
2. Example of instanceof operator
3. Applying the instanceof operator with a variable the have null value
4. Downcasting with instanceof operator
5. Downcasting without instanceof operator
The java instanceof operator is used to test whether the object is an instance of the
specified type (class or subclass or interface).
The instanceof in java is also known as type comparison operator because it compares the
instance with type. It returns either true or false. If we apply the instanceof operator with
any variable that has null value, it returns false.
88
An object of subclass type is also a type of parent class. For example, if Dog extends Animal
then object of Dog can be referred by either Dog or Animal class.
89
90
Let's take closer look at this, actual object that is referred by a, is an object of Dog class. So
if we downcast it, it is fine. But what will happen if we write:
1. Animal a=new Animal();
2. Dog.method(a);
3. //Now ClassCastException but not in case of instanceof operator
91
Before learning java abstract class, let's understand the abstraction in java first.
Abstraction in Java
Abstraction is a process of hiding the implementation details and showing only
functionality to the user.
Another way, it shows only important things to the user and hides the internal details for
example sending sms, you just type the text and send the message. You don't know the
internal processing about the message delivery.
Abstraction lets you focus on what the object does instead of how it does it.
abstract method
A method that is declared as abstract and does not have implementation is known as
abstract method.
92
File: TestAbstraction1.java
1.
2.
3.
4.
5.
6.
7.
8.
93
9. class Circle1 extends Shape{
10. void draw(){System.out.println("drawing circle");}
11. }
12.
13. //In real scenario, method is called by programmer or user
14. class TestAbstraction1{
15. public static void main(String args[]){
16. Shape s=new Circle1();//In real scenario, object is provided through method e.g. getShape
() method
17. s.draw();
18. }
19. }
Test it Now
drawing circle
94
File: TestAbstraction2.java
1. //example of abstract class that have method body
2. abstract class Bike{
3.
Bike(){System.out.println("bike is created");}
4.
abstract void run();
5.
void changeGear(){System.out.println("gear changed");}
6. }
7.
8. class Honda extends Bike{
9. void run(){System.out.println("running safely..");}
10. }
11. class TestAbstraction2{
12. public static void main(String args[]){
13. Bike obj = new Honda();
14. obj.run();
15. obj.changeGear();
16. }
17. }
Test it Now
bike is created
running safely..
gear changed
Rule: If there is any abstract method in a class, that class must be abstract.
1. class Bike12{
2. abstract void run();
3. }
Test it Now
compile time error
Rule: If you are extending any abstract class that have abstract method, you must
either provide the implementation of the method or make this class abstract.
95
Note: If you are beginner to java, learn interface first and skip this example.
1. interface A{
2. void a();
3. void b();
4. void c();
5. void d();
6. }
7.
8. abstract class B implements A{
9. public void c(){System.out.println("I am C");}
10. }
11.
12. class M extends B{
13. public void a(){System.out.println("I am a");}
14. public void b(){System.out.println("I am b");}
15. public void d(){System.out.println("I am d");}
16. }
17.
18. class Test5{
19. public static void main(String args[]){
20. A a=new M();
21. a.a();
22. a.b();
23. a.c();
24. a.d();
25. }}
Test it Now
Output:I am a
I am b
I am c
I am d
Interface in Java
1. Interface
2. Example of Interface
3. Multiple inheritance by Interface
4. Why multiple inheritance is supported in Interface while it is not supported in case of class.
5. Marker Interface
6. Nested Interface
An interface in java is a blueprint of a class. It has static constants and abstract methods
only.
96
The interface in java is a mechanism to achieve fully abstraction. There can be only
abstract methods in the java interface not method body. It is used to achieve fully
abstraction and multiple inheritance in Java.
Java Interface also represents IS-A relationship.
It cannot be instantiated just like abstract class.
The java compiler adds public and abstract keywords before the interface method
and public, static and final keywords before data members.
In other words, Interface fields are public, static and final bydefault, and methods are public
and abstract.
97
98
99
1. interface Printable{
2. void print();
3. }
4.
5. interface Showable{
6. void show();
7. }
8.
9. class A7 implements Printable,Showable{
10.
11. public void print(){System.out.println("Hello");}
12. public void show(){System.out.println("Welcome");}
13.
14. public static void main(String args[]){
15. A7 obj = new A7();
16. obj.print();
17. obj.show();
18. }
19. }
Test it Now
Output:Hello
Welcome
100
1. interface Printable{
2. void print();
3. }
4.
5. interface Showable{
6. void print();
7. }
8.
9. class testinterface1 implements Printable,Showable{
10.
11. public void print(){System.out.println("Hello");}
12.
13. public static void main(String args[]){
14. testinterface1 obj = new testinterface1();
15. obj.print();
16. }
17. }
Test it Now
Hello
As you can see in the above example, Printable and Showable interface have same methods
but its implementation is provided by class A, so there is no ambiguity.
Interface inheritance
A class implements interface but one interface extends another interface .
1. interface Printable{
2. void print();
3. }
4. interface Showable extends Printable{
5. void show();
6. }
7. class Testinterface2 implements Showable{
8.
9. public void print(){System.out.println("Hello");}
10. public void show(){System.out.println("Welcome");}
11.
12. public static void main(String args[]){
13. Testinterface2 obj = new Testinterface2();
14. obj.print();
15. obj.show();
16. }
17. }
Test it Now
Hello
101
Welcome
Java Package
1. Java Package
2. Example of package
3. Accessing package
1. By import packagename.*
2. By import packagename.classname
3. By fully qualified name
4. Subpackage
5. Sending class file to another directory
6. -classpath switch
7. 4 ways to load the class file or jar file
8. How to put two public class in a package
9. Static Import
10. Package class
102
103
//save as Simple.java
package mypack;
public class Simple{
public static void main(String args[]){
System.out.println("Welcome to package");
}
}
104
1) Using packagename.*
If you use package.* then all the classes and interfaces of this package will be accessible
but not subpackages.
The import keyword is used to make the classes and interface of another package
accessible to the current package.
2) Using packagename.classname
If you import package.classname then only declared class of this package will be accessible.
105
//save by A.java
package pack;
public class A{
public void msg(){System.out.println("Hello");}
}
//save by B.java
package mypack;
class B{
public static void main(String args[]){
pack.A obj = new pack.A();//using fully qualified name
obj.msg();
}
106
9. }
Output:Hello
Note: Sequence of the program must be package then import then class.
Subpackage in java
Package inside the package is called the subpackage. It should be created to categorize
the package further.
Let's take an example, Sun Microsystem has definded a package named java that contains
many classes like System, String, Reader, Writer, Socket etc. These classes represent a
particular group e.g. Reader and Writer classes are for Input/Output operation, Socket and
ServerSocket classes are for networking etc and so on. So, Sun has subcategorized the java
package into subpackages such as lang, net, io etc. and put the Input/Output related
classes in io package, Server and ServerSocket classes in net packages and so on.
107
Example of Subpackage
1. package com.javatpoint.core;
2. class Simple{
3.
public static void main(String args[]){
4.
System.out.println("Hello subpackage");
5.
}
6. }
To Compile: javac -d . Simple.java
To Run: java com.javatpoint.core.Simple
Output:Hello subpackage
108
1.
2.
3.
4.
5.
6.
7.
8.
//save as Simple.java
package mypack;
public class Simple{
public static void main(String args[]){
System.out.println("Welcome to package");
}
}
To Compile:
e:\sources> javac -d c:\classes Simple.java
To Run:
To run this program from e:\source directory, you need to set classpath of the directory
where the class file resides.
e:\sources> set classpath=c:\classes;.;
e:\sources> java mypack.Simple
Temporary
o By setting the classpath in the command prompt
o By -classpath switch
Permanent
o By setting the classpath in the environment variables
o By creating the jar file, that contains all the class files, and copying the jar file
in the jre/lib/ext folder.
109
Rule: There can be only one public class in a java source file and it must be saved
by the public class name.
1.
2.
3.
4.
5.
//save as A.java
package javatpoint;
public class A{}
//save as B.java
package javatpoint;
public class B{}
Static Import:
The static import feature of Java 5 facilitate the java programmer to access any static
member of a class directly. There is no need to qualify it by the class name.
Less coding is required if you have access any static member of a class oftenly.
If you overuse the static import feature, it makes the program unreadable and
unmaintainable.
110
2. class StaticImportExample{
3.
public static void main(String args[]){
4.
5.
out.println("Hello");//Now no need of System.out
6.
out.println("Java");
7.
8. }
9. }
10.
Test it Now
Output:Hello
Java
111
9.
System.out.println(a2+" "+a3);
10. }
11. }
12.
Test it Now
Output:50 5
112
Output:50
113
Output:int int
114
There are two types of modifiers in java: access modifiers and non-access modifiers.
The access modifiers in java specifies accessibility (scope) of a data member, method,
constructor or class.
There are 4 types of java access modifiers:
1.
2.
3.
4.
private
default
protected
public
There are many non-access modifiers such as static, abstract, synchronized, native, volatile,
transient etc. Here, we will learn access modifiers.
115
2.
3.
4.
5.
6.
7.
8.
9.
//save by A.java
package pack;
class A{
void msg(){System.out.println("Hello");}
}
//save by B.java
package mypack;
import pack.*;
class B{
public static void main(String args[]){
A obj = new A();//Compile Time Error
obj.msg();//Compile Time Error
}
}
In the above example, the scope of class A and its method msg() is default so it cannot be
accessed from outside the package.
116
//save by A.java
package pack;
public class A{
public void msg(){System.out.println("Hello");}
117
6. }
1. //save by B.java
2.
3. package mypack;
4. import pack.*;
5.
6. class B{
7.
public static void main(String args[]){
8.
A obj = new A();
9.
obj.msg();
10. }
11. }
Output:Hello
Access Modifier
within class
within package
outside package
Private
Default
Protected
Public
class A{
protected void msg(){System.out.println("Hello java");}
}
public class Simple extends A{
void msg(){System.out.println("Hello java");}//C.T.Error
public static void main(String args[]){
118
8.
Simple obj=new Simple();
9.
obj.msg();
10. }
11. }
The default modifier is more restrictive than protected. That is why there is compile time
error.
Encapsulation in Java
Encapsulation in java is a process of wrapping code and data together into a single unit,
for example capsule i.e. mixed of several medicines.
We can create a fully encapsulated class in java by making all the data members of the
class private. Now we can use setter and getter methods to set and get the data in it.
The Java Bean class is the example of fully encapsulated class.
//save as Student.java
package com.javatpoint;
public class Student{
private String name;
public String getName(){
119
7. return name;
8. }
9. public void setName(String name){
10. this.name=name
11. }
12. }
1. //save as Test.java
2. package com.javatpoint;
3. class Test{
4. public static void main(String[] args){
5. Student s=new Student();
6. s.setname("vijay");
7. System.out.println(s.getName());
8. }
9. }
Compile By: javac -d . Test.java
Run By: java com.javatpoint.Test
Output: vijay
120
Method
public final ClassgetClass()
Description
returns the Class class object of this object. The
Class class can further be used to get the metadata
of this class.
CloneNotSupportedException
object.
121
monitor.
timeout)throws InterruptedException
nanos)throws InterruptedException
InterruptedException
Throwable
122
The clone() method is defined in the Object class. Syntax of the clone() method is as
follows:
1. protected Object clone() throws CloneNotSupportedException
123
Output:101 amit
101 amit
Java Array
Normally, array is a collection of similar type of elements that have contiguous memory
location.
Java array is an object the contains elements of similar data type. It is a data structure
where we store similar elements. We can store only fixed set of elements in a java array.
Array in java is index based, first element of the array is stored at 0 index.
Code Optimization: It makes the code optimized, we can retrieve or sort the data
easily.
Random access: We can get any data located at any index position.
Size Limit: We can store only fixed size of elements in the array. It doesn't grow its
size at runtime. To solve this problem, collection framework is used in java.
124
125
126
11. public static void main(String args[]){
12.
13. int a[]={33,3,4,5};
14. min(a);//passing array to method
15.
16. }}
Test it Now
Output:3
arr[0][0]=1;
arr[0][1]=2;
arr[0][2]=3;
arr[1][0]=4;
arr[1][1]=5;
arr[1][2]=6;
arr[2][0]=7;
arr[2][1]=8;
arr[2][2]=9;
class Testarray3{
public static void main(String args[]){
//declaring and initializing 2D array
int arr[][]={{1,2,3},{2,4,5},{4,4,5}};
//printing 2D array
for(int i=0;i<3;i++){
127
9. for(int j=0;j<3;j++){
10. System.out.print(arr[i][j]+" ");
11. }
12. System.out.println();
13. }
14.
15. }}
Test it Now
Output:1 2 3
2 4 5
4 4 5
128
3.
4.
5.
6.
7.
8.
9.
}
10. }
Test
Output:caffein
129
130
13. op.change(op);//passing object
14. System.out.println("after change "+op.data);
15.
16. }
17. }
strictfp keyword
The strictfp keyword ensures that you will get the same result on every platform if you
perform operations in the floating-point variable. The precision may differ from platform
to platform that is why java programming language have provided the strictfp keyword,
so that you get same result on every platform. So, now you have better control over the
floating-point arithmetic.
class B{
strictfp abstract void m();//Illegal combination of modifiers
}
class B{
strictfp int data=10;//modifier strictfp not allowed here
}
class B{
strictfp B(){}//modifier strictfp not allowed here
}
131
We can create document api in java by the help of javadoc tool. In the java file, we must
use the documentation comment /**... */ to post information for the class, method,
constructor, fields etc.
Let's see the simple class that contains documentation comment.
1.
2.
3.
4.
5.
6.
7.
package com.abc;
/** This class is a user-defined class that contains one methods cube.*/
public class M{
/** The cube method prints cube of the given number */
public static void cube(int n){System.out.println(n*n*n);}
}
To create the document API, you need to use the javadoc tool followed by java file name.
There is no need to compile the javafile.
On the command prompt, you need to write:
javadoc M.java
to generate the document api. Now, there will be created a lot of html files. Open the
index.html file to get the information about the classes.
132
class CommandLineExample{
public static void main(String args[]){
System.out.println("Your first argument is: "+args[0]);
}
}
compile by > javac CommandLineExample.java
run by > java CommandLineExample sonoo
Output: Your first argument is: sonoo
class A{
public static void main(String args[]){
for(int i=0;i<args.length;i++)
System.out.println(args[i]);
}
}
compile by > javac A.java
run by > java A sonoo jaiswal 1 3 abc
Output: sonoo
jaiswal
1
3
abc
Java String
1. Java String Handling
2. How to create string object
1. String literal
2. new keyword
133
Java String provides a lot of concepts that can be performed on a string such as compare,
concat, equals, split, length, replace, compareTo, intern, substring etc.
In java, string is basically an object that represents sequence of char values.
An array of characters works same as java string. For example:
1. char[] ch={'j','a','v','a','t','p','o','i','n','t'};
2. String s=new String(ch);
is same as:
1. String s="javatpoint";
The java.lang.String class
implements Serializable, Comparable and CharSequence interfaces.
The java String is immutable i.e. it cannot be changed but a new instance is created. For
mutable class, you can use StringBuffer and StringBuilder class.
We will discuss about immutable string later. Let's first understand what is string in java
and how to create the string object.
1) String Literal
Java String literal is created by using double quotes. For Example:
134
1. String s="welcome";
Each time you create a string literal, the JVM checks the string constant pool first. If the
string already exists in the pool, a reference to the pooled instance is returned. If string
doesn't exist in the pool, a new string instance is created and placed in the pool. For
example:
1. String s1="Welcome";
2. String s2="Welcome";//will not create new instance
In the above example only one object will be created. Firstly JVM will not find any string
object with the value "Welcome" in string constant pool, so it will create a new object. After
that it will find the string with the value "Welcome" in the pool, it will not create new object
but will return the reference to the same instance.
135
Note: String objects are stored in a special memory area known as string constant
pool.
2) By new keyword
1. String s=new String("Welcome");//creates two objects and one reference variable
In such case, JVM will create a new string object in normal(non pool) heap memory and the
literal "Welcome" will be placed in the string constant pool. The variable s will refer to the
object in heap(non pool).
136
No.
1
Method
char charAt(int index)
Description
returns char value for the particular
index
int length()
args)
locale
index
boolean contains(CharSequence s)
CharSequence... elements)
10
137
11
boolean isEmpty()
12
13
14
15
new)
CharSequence
String trim()
16
17
18
String intern()
19
20
21
22
Do You Know ?
138
Concept of String
Immutable String
String Comparison
String Concatenation
Concept of Substring
String class methods and its usage
StringBuffer class
StringBuilder class
Creating Immutable class
toString() method
StringTokenizer class
139
As you can see in the above figure that two objects are created but s reference variable still
refers to "Sachin" not to "Sachin Tendulkar".
But if we explicitely assign it to the reference variable, it will refer to "Sachin Tendulkar"
object.For example:
1. class Testimmutablestring1{
2. public static void main(String args[]){
3.
String s="Sachin";
4.
s=s.concat(" Tendulkar");
5.
System.out.println(s);
6. }
7. }
Test it Now
Output:Sachin Tendulkar
140
In such case, s points to the "Sachin Tendulkar". Please notice that still sachin object is not
modified.
We can compare two given strings on the basis of content and reference.
It is used in authentication (by equals() method), sorting (by compareTo()
method), reference matching (by == operator) etc.
There are three ways to compare String objects:
1. By equals() method
2. By = = operator
3. By compareTo() method
1) By equals() method
equals() method compares the original content of the string.It compares values of string
141
1. class Teststringcomparison1{
2. public static void main(String args[]){
3.
4.
String s1="Sachin";
5.
String s2="Sachin";
6.
String s3=new String("Sachin");
7.
String s4="Saurav";
8.
9.
System.out.println(s1.equals(s2));//true
10. System.out.println(s1.equals(s3));//true
11. System.out.println(s1.equals(s4));//false
12. }
13. }
Test it Now
Output:true
true
false
1. //Example of equalsIgnoreCase(String) method
2. class Teststringcomparison2{
3. public static void main(String args[]){
4.
5.
String s1="Sachin";
6.
String s2="SACHIN";
7.
8.
System.out.println(s1.equals(s2));//false
9.
System.out.println(s1.equalsIgnoreCase(s3));//true
10. }
11. }
Test it Now
Output:false
true
2) By == operator
The = = operator compares references not values.
1. //<b><i>Example of == operator</i></b>
2.
3. class Teststringcomparison3{
4. public static void main(String args[]){
142
5.
6.
String s1="Sachin";
7.
String s2="Sachin";
8.
String s3=new String("Sachin");
9.
10. System.out.println(s1==s2);//true (because both refer to same instance)
11. System.out.println(s1==s3);//false(because s3 refers to instance created in nonpool)
12. }
13. }
Test it Now
Output:true
false
3) By compareTo() method:
compareTo() method compares values and returns an int which tells if the values
compare less than, equal, or greater than.
Suppose s1 and s2 are two string variables.If:
s1 == s2 :0
s1 > s2 :positive value
s1 < s2 :negative value
143
Concating strings form a new string i.e. the combination of multiple strings.
There are two ways to concat string objects:
1. By + (string concatenation) operator
2. By concat() method
144
2) By concat() method
concat() method concatenates the specified string to the end of current string.
Syntax:public String concat(String another){}
1. //<b><i>Example of concat(String) method</i></b>
2.
3. class TestStringConcatenation3{
4. public static void main(String args[]){
5.
6.
String s1="Sachin ";
7.
String s2="Tendulkar";
8.
9.
String s3=s1.concat(s2);
10.
11. System.out.println(s3);//Sachin Tendulkar
12. }
13. }
Test it Now
Output:Sachin Tendulkar
Substring in Java
A part of string is called substring. In other words, substring is a subset of another string.
In case of substring startIndex starts from 0 and endIndex starts from 1 or startIndex is
inclusive and endIndex is exclusive.
145
You can get substring from the given String object by one of the two methods:
1. public String substring(int startIndex): This method returns new String object
containing the substring of the given string from specified startIndex (inclusive).
2. public String substring(int startIndex,int endIndex): This method returns new
String object containing the substring of the given string from specified startIndex to
endIndex.
In case of string:
146
String s="Sachin";
System.out.println(s.toUpperCase());//SACHIN
System.out.println(s.toLowerCase());//sachin
System.out.println(s);//Sachin(no change in original)
Test it Now
SACHIN
sachin
Sachin
147
3. System.out.println(s.charAt(3));//h
Test it Now
S
h
148
StringBuffer class:
The StringBuffer class is used to created mutable (modifiable) string. The StringBuffer
class is same as String except it is mutable i.e. it can be changed.
149
substring from the specified beginIndex and endIndex.
class A{
public static void main(String args[]){
StringBuffer sb=new StringBuffer("Hello ");
sb.append("Java");//now original string is changed
System.out.println(sb);//prints Hello Java
}
}
class A{
public static void main(String args[]){
StringBuffer sb=new StringBuffer("Hello ");
sb.insert(1,"Java");//now original string is changed
System.out.println(sb);//prints HJavaello
}
}
class A{
public static void main(String args[]){
StringBuffer sb=new StringBuffer("Hello");
sb.replace(1,3,"Java");
150
7. System.out.println(sb);//prints HJavalo
8. }
9. }
class A{
public static void main(String args[]){
StringBuffer sb=new StringBuffer("Hello");
sb.delete(1,3);
System.out.println(sb);//prints Hlo
}
}
class A{
public static void main(String args[]){
StringBuffer sb=new StringBuffer("Hello");
sb.reverse();
System.out.println(sb);//prints olleH
}
}
class A{
public static void main(String args[]){
StringBuffer sb=new StringBuffer();
System.out.println(sb.capacity());//default 16
sb.append("Hello");
151
8. System.out.println(sb.capacity());//now 16
9.
10. sb.append("java is my favourite language");
11. System.out.println(sb.capacity());//now (16*2)+2=34 i.e (oldcapacity*2)+2
12. }
13. }
StringBuilder class:
The StringBuilder class is used to create mutable (modifiable) string. The StringBuilder
class is same as StringBuffer class except that it is non-synchronized. It is available since
JDK1.5.
152
capacity as length.
class A{
public static void main(String args[]){
StringBuilder sb=new StringBuilder("Hello ");
sb.append("Java");//now original string is changed
System.out.println(sb);//prints Hello Java
}
}
153
class A{
public static void main(String args[]){
StringBuilder sb=new StringBuilder("Hello ");
sb.insert(1,"Java");//now original string is changed
System.out.println(sb);//prints HJavaello
}
}
class A{
public static void main(String args[]){
StringBuilder sb=new StringBuilder("Hello");
sb.replace(1,3,"Java");
System.out.println(sb);//prints HJavalo
}
}
class A{
public static void main(String args[]){
StringBuilder sb=new StringBuilder("Hello");
sb.delete(1,3);
System.out.println(sb);//prints Hlo
}
}
154
1.
2.
3.
4.
5.
6.
7.
8.
9.
class A{
public static void main(String args[]){
StringBuilder sb=new StringBuilder("Hello");
sb.reverse();
System.out.println(sb);//prints olleH
}
}
155
11. System.out.println(sb.capacity());//now (16*2)+2=34 i.e (oldcapacity*2)+2
12.
13. sb.ensureCapacity(10);//now no change
14. System.out.println(sb.capacity());//now 34
15.
16. sb.ensureCapacity(50);//now (34*2)+2
17. System.out.println(sb.capacity());//now 70
18.
19. }
20. }
The instance variable of the class is final i.e. we cannot change the value of it
after creating an object.
The class is final so we cannot create the subclass.
There is no setter methods i.e. we have no option to change the value of the
instance variable.
156
157
calls toString() method, overriding this method will return the specified values. Let's
understand it with the example given below:
StringTokenizer in Java
1. StringTokenizer
2. Methods of StringTokenizer
3. Example of StringTokenizer
The java.util.StringTokenizer class allows you to break a string into tokens. It is simple
way to break string.
158
It doesn't provide the facility to differentiate numbers, quoted strings, identifiers etc. like
StreamTokenizer class. We will discuss about the StreamTokenizer class in I/O chapter.
Constructor
Description
StringTokenizer(String str)
StringTokenizer(String str,
String delim)
StringTokenizer(String str,
returnValue)
Public method
Description
boolean hasMoreTokens()
String nextToken()
boolean hasMoreElements()
159
Object nextElement()
int countTokens()
160
Java Regex
The Java Regex or Regular Expression is an API to define pattern for searching or
manipulating strings.
It is widely used to define constraint on strings such as password and email validation. After
learning java regex tutorial, you will be able to test your own regular expressions by the
Java Regex Tester Tool.
Java Regex API provides 1 interface and 3 classes in java.util.regex package.
java.util.regex package
It provides following classes and interface for regular expressions. The Matcher and Pattern
classes are widely used in java regular expression.
1.
2.
3.
4.
MatchResult interface
Matcher class
Pattern class
PatternSyntaxException class
Matcher class
It implements MatchResult interface. It is a regex engine i.e. used to perform match
operations on a character sequence.
No.
Method
Description
boolean matches()
boolean find()
boolean find(int
finds the next expression that matches the pattern from the given
start)
start number.
161
Pattern class
It is the compiled version of a regular expression. It is used to define a pattern for the regex
engine.
No.
1
Method
Description
regex)
pattern.
Matcher matcher(CharSequence
input)
pattern.
String pattern()
162
13. boolean b3 = Pattern.matches(".s", "as");
14.
15. System.out.println(b+" "+b2+" "+b3);
16. }}
Test it Now
Output
true true true
import java.util.regex.*;
class RegexExample2{
public static void main(String args[]){
System.out.println(Pattern.matches(".s", "as"));//true (2nd char is s)
System.out.println(Pattern.matches(".s", "mk"));//false (2nd char is not s)
System.out.println(Pattern.matches(".s", "mst"));//false (has more than 2 char)
System.out.println(Pattern.matches(".s", "amms"));//false (has more than 2 char)
System.out.println(Pattern.matches("..s", "mas"));//true (3rd char is s)
}}
Test it Now
Character Class
Description
[abc]
a, b, or c (simple class)
[^abc]
[a-zA-Z]
[a-d[m-p]]
[a-z&&[def]]
d, e, or f (intersection)
163
[a-z&&[^bc]]
[a-z&&[^m-p]]
import java.util.regex.*;
class RegexExample3{
public static void main(String args[]){
System.out.println(Pattern.matches("[amn]", "abcd"));//false (not a or m or n)
System.out.println(Pattern.matches("[amn]", "a"));//true (among a or m or n)
System.out.println(Pattern.matches("[amn]", "ammmna"));//false (m and a comes more th
an once)
7. }}
Test it Now
Regex Quantifiers
The quantifiers specify the number of occurrences of a character.
Regex
Description
X?
X+
X*
X{n}
X{n,}
X{y,z}
164
import java.util.regex.*;
class RegexExample4{
public static void main(String args[]){
System.out.println("? quantifier ....");
System.out.println(Pattern.matches("[amn]?", "a"));//true (a or m or n comes one time)
System.out.println(Pattern.matches("[amn]?", "aaa"));//false (a comes more than one time
)
7. System.out.println(Pattern.matches("[amn]?", "aammmnn"));//false (a m and n comes mor
e than one time)
8. System.out.println(Pattern.matches("[amn]?", "aazzta"));//false (a comes more than one ti
me)
9. System.out.println(Pattern.matches("[amn]?", "am"));//false (a or m or n must come one ti
me)
10.
11. System.out.println("+ quantifier ....");
12. System.out.println(Pattern.matches("[amn]+", "a"));//true (a or m or n once or more times
)
13. System.out.println(Pattern.matches("[amn]+", "aaa"));//true (a comes more than one time
)
14. System.out.println(Pattern.matches("[amn]+", "aammmnn"));//true (a or m or n comes mo
re than once)
15. System.out.println(Pattern.matches("[amn]+", "aazzta"));//false (z and t are not matching
pattern)
16.
17. System.out.println("* quantifier ....");
18. System.out.println(Pattern.matches("[amn]*", "ammmna"));//true (a or m or n may come
zero or more times)
19.
20. }}
Test it Now
Regex Metacharacters
The regular expression metacharacters work as a short codes.
Regex
Description
\d
165
\D
\s
\S
\w
\W
\b
A word boundary
\B
import java.util.regex.*;
class RegexExample5{
public static void main(String args[]){
System.out.println("metacharacters d....");\\d means digit
166
/*Create a regular expression that accepts alpha numeric characters only. Its
length must be 6 characters long only.*/
import java.util.regex.*;
class RegexExample6{
public static void main(String args[]){
System.out.println(Pattern.matches("[a-zA-Z0-9]{6}", "arun32"));//true
System.out.println(Pattern.matches("[a-zA-Z09]{6}", "kkvarun32"));//false (more than 6 char)
9. System.out.println(Pattern.matches("[a-zA-Z0-9]{6}", "JA2Uk2"));//true
10. System.out.println(Pattern.matches("[a-zA-Z09]{6}", "arun$2"));//false ($ is not matched)
11. }}
Test it Now
167
1. Exception Handling
2. Advantage of Exception Handling
3. Hierarchy of Exception classes
4. Types of Exception
5. Scenarios where exception may occur
The exception handling in java is one of the powerful mechanism to handle the runtime
errors so that normal flow of the application can be maintained.
In this page, we will learn about java exception, its type and the difference between
checked and unchecked exceptions.
What is exception
Dictionary Meaning: Exception is an abnormal condition.
In java, exception is an event that disrupts the normal flow of the program. It is an object
which is thrown at runtime.
statement
statement
statement
statement
statement
statement
statement
statement
1;
2;
3;
4;
5;//exception occurs
6;
7;
8;
168
9. statement 9;
10. statement 10;
Suppose there is 10 statements in your program and there occurs an exception at
statement 5, rest of the code will not be executed i.e. statement 6 to 10 will not run. If we
perform exception handling, rest of the exception will be executed. That is why we use
exception handling in java.
Do You Know ?
169
Types of Exception
There are mainly two types of exceptions: checked and unchecked where error is considered
as unchecked exception. The sun microsystem says there are three types of exceptions:
1. Checked Exception
2. Unchecked Exception
3. Error
170
2) Unchecked Exception
The classes that extend RuntimeException are known as unchecked exceptions e.g.
ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException etc.
Unchecked exceptions are not checked at compile-time rather they are checked at runtime.
3) Error
Error is irrecoverable e.g. OutOfMemoryError, VirtualMachineError, AssertionError etc.
171
try
catch
finally
throw
throws
try block
Enclose the code that might throw an exception in try block. It must be used within the
method and must be followed by either catch or finally block.
172
2. ...
3. }finally{}
catch block
Catch block is used to handle the Exception. It must be used after the try block.
As displayed in the above example, rest of the code is not executed i.e. rest of the
code... statement is not printed. Let's see what happens behind the scene:
173
The JVM firstly checks whether the exception is handled or not. If exception is not
handled, JVM provides a default exception handler that performs the following tasks:
But if exception is handled by the application programmer, normal flow of the application
is maintained i.e. rest of the code is executed.
174
2.
public static void main(String args[]){
3.
try{
4.
int data=50/0;
5.
6.
}catch(ArithmeticException e){System.out.println(e);}
7.
8.
System.out.println("rest of the code...");
9. }
10. }
Test it Now
Output:Exception in thread main java.lang.ArithmeticException:/ by zero
rest of the code...
Now, as displayed in the above example, rest of the code is executed i.e. rest of the
code... statement is printed.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11. System.out.println("rest of the code...");
12. }
13. }
Test it Now
Output:task1 completed
rest of the code...
Rule:At a time only one Exception is occured and at a time only one catch block is
executed.
Rule:All catch blocks must be ordered from most specific to most general i.e. catch
for ArithmeticException must come before catch for Exception .
1. class TestMultipleCatchBlock1{
175
2.
public static void main(String args[]){
3.
try{
4.
int a[]=new int[5];
5.
a[5]=30/0;
6.
}
7.
catch(Exception e){System.out.println("common task completed");}
8.
catch(ArithmeticException e){System.out.println("task1 is completed");}
9.
catch(ArrayIndexOutOfBoundsException e){System.out.println("task 2 completed");}
10.
11. System.out.println("rest of the code...");
12. }
13. }
Test it Now
Output:Compile-time error
Syntax:
1. ....
2. try
3. {
4.
statement 1;
5.
statement 2;
6.
try
7.
{
8.
statement 1;
9.
statement 2;
10.
}
11.
catch(Exception e)
12.
{
13.
}
14. }
15. catch(Exception e)
16. {
17. }
18. ....
176
Example:
Example of nested try block
1. class Excep6{
2. public static void main(String args[]){
3.
try{
4.
try{
5.
System.out.println("going to divide");
6.
int b =39/0;
7.
}catch(ArithmeticException e){System.out.println(e);}
8.
9.
try{
10.
int a[]=new int[5];
11.
a[5]=4;
12.
}catch(ArrayIndexOutOfBoundsException e){System.out.println(e);}
13.
14.
System.out.println("other statement);
15. }catch(Exception e){System.out.println("handeled");}
16.
17. System.out.println("normal flow..");
18. }
19. }
finally block
The finally block is a block that is always executed. It is mainly used to perform some
important tasks such as closing connection, stream etc.
177
finally block can be used to put "cleanup" code such as closing a file,closing
connection etc.
case 1
Program in case exception does not occur
178
1. class TestFinallyBlock{
2.
public static void main(String args[]){
3.
try{
4.
int data=25/5;
5.
System.out.println(data);
6.
}
7.
catch(NullPointerException e){System.out.println(e);}
8.
9.
finally{System.out.println("finally block is always executed");}
10.
11. System.out.println("rest of the code...");
12. }
13. }
Test it Now
Output:5
finally block is always executed
rest of the code...
case 2
Program in case exception occured but not handled
1. class TestFinallyBlock1{
2.
public static void main(String args[]){
3.
try{
4.
int data=25/0;
5.
System.out.println(data);
6.
}
7.
catch(NullPointerException e){System.out.println(e);}
8.
9.
finally{System.out.println("finally block is always executed");}
10.
11. System.out.println("rest of the code...");
12. }
13. }
Test it Now
Output:finally block is always executed
Exception in thread main java.lang.ArithmeticException:/ by zero
case 3
Program in case exception occured and handled
1. public class TestFinallyBlock2{
2.
public static void main(String args[]){
3.
try{
4.
int data=25/0;
5.
System.out.println(data);
6.
}
7.
catch(ArithmeticException e){System.out.println(e);}
179
8.
9.
finally{System.out.println("finally block is always executed");}
10.
11. System.out.println("rest of the code...");
12. }
13. }
Test it Now
Output:Exception in thread main java.lang.ArithmeticException:/ by zero
finally block is always executed
rest of the code...
Rule: For each try block there can be zero or more catch blocks, but only one finally
block.
Note: The finally block will not be executed if program exits(either by calling
System.exit() or by causing a fatal error that causes the process to abort).
throw keyword
The throw keyword is used to explictily throw an exception.
We can throw either checked or uncheked exception. The throw keyword is mainly used
to throw custom exception. We will see custom exceptions later.
180
12.
System.out.println("rest of the code...");
13. }
14. }
Test it Now
Output:Exception in thread main java.lang.ArithmeticException:not valid
Exception propagation:
An exception is first thrown from the top of the stack and if it is not caught, it drops
down the call stack to the previous method,If not caught there, the exception again
drops down to the previous method, and so on until they are caught or until they reach
the very bottom of the call stack.This is called exception propagation.
181
In the above example exception occurs in m() method where it is not handled,so it is
propagated to previous n() method where it is not handled, again it is propagated to p()
method where exception is handled.
Exception can be handled in any method in call stack either in main() method,p()
method,n() method or m() method.
182
18. }
Test it Now
Output:Compile Time Error
throws keyword
The throws keyword is used to declare an exception. It gives an information to the
programmer that there may occur an exception so it is better for the programmer to
provide the exception handling code so that normal flow can be maintained.
Exception Handling is mainly used to handle the checked exceptions. If there occurs any
unchecked exception such as NullPointerException, it is programmers fault that he is not
performing check up before the code being used.
183
8.
}
9.
void p(){
10. try{
11.
n();
12. }catch(Exception e){System.out.println("exception handled");}
13. }
14. public static void main(String args[]){
15. Testthrows1 obj=new Testthrows1();
16. obj.p();
17. System.out.println("normal flow...");
18. }
19. }
Test it Now
Output:exception handled
normal flow...
In case you handle the exception, the code will be executed fine whether exception
occurs during the program or not.
1. import java.io.*;
2. class M{
3. void method()throws IOException{
4.
throw new IOException("device error");
5. }
6. }
7.
8.
9. public class Testthrows2{
10. public static void main(String args[]){
11.
try{
12.
Testthrows2 t=new Testthrows2();
13.
t.method();
14.
}catch(Exception e){System.out.println("exception handled");}
15.
16.
System.out.println("normal flow...");
17. }
18. }
Test it Now
184
Output:exception handled
normal flow...
A)In case you declare the exception, if exception does not occur, the code will be
executed fine.
B)In case you declare the exception if exception occures, an exception will be thrown
at runtime because throws does not handle the exception.
1.
2.
3.
4.
5.
6.
7.
8.
9. class Testthrows3{
10. public static void main(String args[])throws IOException{//declare exception
11.
Testthrows3 t=new Testthrows3();
12.
t.method();
13.
14.
System.out.println("normal flow...");
15. }
16. }
Test it Now
Output:device operation performed
normal flow...
B)Program if exception occurs
1. import java.io.*;
2. class M{
3. void method()throws IOException{
4.
throw new IOException("device error");
5. }
6. }
7.
8.
9. class Testthrows4{
10. public static void main(String args[])throws IOException{//declare exception
11.
Testthrows4 t=new Testthrows4();
12.
t.method();
13.
14.
System.out.println("normal flow...");
15. }
16. }
185
Test it Now
Output:Runtime Exception
throws keyword
without throws.
throws.
186
declare parent exception.
187
Output:child
188
15. }
Test it Now
Output:child
189
Custom Exception
If you are creating your own Exception that is known as custom exception or user1.
2.
3.
4.
5.
defined exception.
class InvalidAgeException extends Exception{
InvalidAgeException(String s){
super(s);
}
}
1. class TestCustomException1{
2.
3.
static void validate(int age)throws InvalidAgeException{
4.
if(age<18)
5.
throw new InvalidAgeException("not valid");
6.
else
7.
System.out.println("welcome to vote");
8.
}
9.
10. public static void main(String args[]){
11.
try{
12.
validate(13);
13.
}catch(Exception m){System.out.println("Exception occured: "+m);}
14.
15.
System.out.println("rest of the code...");
16. }
17. }
Test it Now
Output:Exception occured: InvalidAgeException:not valid
rest of the code...
190
Do You Know ?
What is the internal code generated by the compiler for member inner class ?
What are the two ways to create annonymous inner class ?
Can we access the non-final local variable inside the local inner class ?
How to access the static nested class ?
Can we define an interface within the class ?
Can we define a class within the interface ?
191
Type
Description
Annonymous Inner
Class
Nested Interface
192
1. class TestMemberOuter1{
2. private int data=30;
3. class Inner{
4.
void msg(){System.out.println("data is "+data);}
5. }
6.
7. void display(){
8.
Inner in=new Inner();
9.
in.msg();
10. }
11. public static void main(String args[]){
12. TestMemberOuter1 obj=new TestMemberOuter1();
13. obj.display();
14. }
15. }
Test it Now
Output:data is 30
193
194
195
8.
System.out.println("nice fruits");
9.
}
10. }
import java.io.PrintStream;
static class Emp$1 implements Eatable
{
Emp$1(){}
void eat(){System.out.println("nice fruits");}
}
196
197
198
Output:30 50
In this example, you need to create the instance of static nested class because it has
instance method msg(). But you don't need to create the object of Outer class because
nested class is static and static properties, methods or classes can be accessed without
object.
199
Nested Interface
An interface which is declared within another interface or class is known as nested
interface. The nested interfaces are used to group related interfaces so that they can be
easy to maintain. The nested interface must be referred by the outer interface or class. It
can't be accessed directly.
Nested interface must be public if it is declared inside the interface but it can have
any access modifier if declared within the class.
Nested interfaces are declared static implicitely.
200
3. interface nested_interface_name{
4.
...
5. }
6. }
7.
201
4. }
Stream
A stream is a sequence of data.In Java a stream is composed of bytes. It's called a
stream because it's like a stream of water that continues to flow.
202
Do You Know ?
How to write a common data to multiple files using single stream only ?
How can we access multiple files by single stream ?
How can we improve the performance of Input and Output operation ?
How many ways can we read data from the keyboard?
What is console class ?
How to compress and uncompress the data of a file?
OutputStream
Java application uses an output stream to write data to a destination, it may be a file,an
array,peripheral device or socket.
InputStream
Java application uses an input stream to read data from a source, it may be a file,an
array,peripheral device or socket.
203
OutputStream class
OutputStream class is an abstract class.It is the superclass of all classes representing an
output stream of bytes. An output stream accepts output bytes and sends them to some
sink.
Description
IOException:
stream.
IOException:
output stream.
204
InputStream class
InputStream class is an abstract class.It is the superclass of all classes representing an
input stream of bytes.
Description
IOException:
IOException:
IOException:
205
FileOutputStream class:
A FileOutputStream is an output stream for writing data to a file.
If you have to write primitive values then use FileOutputStream.Instead, for characteroriented data, prefer FileWriter.But you can write byte-oriented as well as characteroriented data.
206
9.
String s="Sachin Tendulkar is my favourite player";
10.
11.
byte b[]=s.getBytes();
12.
fout.write(b);
13.
14.
fout.close();
15.
16.
System.out.println("success...");
17.
}catch(Exception e){system.out.println(e);}
18. }
19. }
Output:success...
FileInputStream class:
A FileInputStream obtains input bytes from a file.It is used for reading streams of raw bytes
such as image data. For reading streams of characters, consider using FileReader.
It should be used to read byte-oriented data.For example, to read image etc.
207
12.
fin.close();
13. }catch(Exception e){system.out.println(e);}
14. }
15. }
Output:Sachin is my favourite player.
ByteArrayOutputStream class:
208
In this stream, the data is written into a byte array. The buffer automatically grows as data
is written to it.
Closing a ByteArrayOutputStream has no effect.
209
SequenceInputStream class:
SequenceInputStream class is used to read data from multiple streams.
210
7.
FileinputStream fin1=new FileinputStream("f1.txt");
8.
FileinputStream fin2=new FileinputStream("f2.txt");
9.
10. SequenceinputStream sis=new SequenceinputStream(fin1,fin2);
11. int i;
12. while((i=sis.read())!=-1)
13. {
14.
System.out.println((char)i);
15. }
16. }
17. }
211
in the Enumeration object. Enumeration object can be get by calling elements method of
the Vector class. Let's see the simple example where we are reading the data from the 4
files.
1. import java.io.*;
2. import java.util.*;
3.
4. class B{
5. public static void main(String args[])throws IOException{
6.
7. //creating the FileInputStream objects for all the files
8. FileInputStream fin=new FileInputStream("A.java");
9. FileInputStream fin2=new FileInputStream("abc2.txt");
10. FileInputStream fin3=new FileInputStream("abc.txt");
11. FileInputStream fin4=new FileInputStream("B.java");
12.
13. //creating Vector object to all the stream
14. Vector v=new Vector();
15. v.add(fin);
16. v.add(fin2);
17. v.add(fin3);
18. v.add(fin4);
19.
20. //creating enumeration object by calling the elements method
21. Enumeration e=v.elements();
22.
23. //passing the enumeration object in the constructor
24. SequenceInputStream bin=new SequenceInputStream(e);
25. int i=0;
26.
27. while((i=bin.read())!=-1){
28. System.out.print((char)i);
29. }
30.
31. bin.close();
32. fin.close();
33. fin2.close();
34. }
35. }
BufferedOutputStream class:
BufferedOutputStream used an internal buffer. It adds more efficiency than to write data
directly into a stream. So, it makes the performance fast.
212
213
next>><<prev
FileWriter class:
FileWriter class is used to write character-oriented data to the file. Sun Microsystem has
suggested not to use the FileInputStream and FileOutputStream classes if you have to
read and write the textual information.
FileReader class:
FileReader class is used to read data from the file.
214
10. fr.close();
11. }
12. }
CharArrayWriter class:
The CharArrayWriter class can be used to write data to multiple files. This class implements
the Appendable interface. Its buffer automatically grows when data is written in this stream.
Calling the close() method on this object has no effect.
InputStreamReader
Console
Scanner
215
DataInputStream etc.
InputStreamReader class:
InputStreamReader class can be used to read data from keyboard.It performs two tasks:
BufferedReader class:
BufferedReader class can be used to read data line by line by readLine() method.
216
217
Syntax:
1. public static Console console(){}
218
java.util.Scanner class:
There are various ways to read input from the keyboard, the java.util.Scanner class is one
of them. The Scanner class breaks the input into tokens using a delimiter which is
whitespace bydefault. It provides many methods to read and parse various primitive values.
public String next(): it returns the next token from the scanner.
public String nextLine(): it moves the scanner position to the next line and
returns the value as a string.
public byte nextByte(): it scans the next token as a byte.
public short nextShort(): it scans the next token as a short value.
public int nextInt(): it scans the next token as an int value.
public long nextLong(): it scans the next token as a long value.
public float nextFloat(): it scans the next token as a float value.
public double nextDouble(): it scans the next token as a double value.
219
3. public static void main(String args[]){
4.
5.
Scanner sc=new Scanner(System.in);
6.
7.
System.out.println("Enter your rollno");
8.
int rollno=sc.nextInt();
9.
System.out.println("Enter your name");
10. String name=sc.next();
11. System.out.println("Enter your fee");
12. double fee=sc.nextDouble();
13.
14. System.out.println("Rollno:"+rollno+" name:"+name+" fee:"+fee);
15.
16. }
17. }
java.io.PrintStream class:
The PrintStream class provides methods to write data to another stream. The
PrintStream class automatically flushes the data so there is no need to call flush()
method. Moreover, its methods don't throw IOException.
public
public
public
public
public
public
public
void
void
void
void
void
void
void
220
221
14. }
DeflaterOutputStream class:
The DeflaterOutputStream class is used to compress the data in the deflate compression
format. It provides facility to the other compression filters, such as GZIPOutputStream.
import java.io.*;
import java.util.zip.*;
class Compress{
public static void main(String args[]){
try{
FileInputStream fin=new FileInputStream("Deflater.java");
222
9.
10. FileOutputStream fout=new FileOutputStream("def.txt");
11. DeflaterOutputStream out=new DeflaterOutputStream(fout);
12.
13. int i;
14. while((i=fin.read())!=-1){
15. out.write((byte)i);
16. out.flush();
17. }
18.
19. fin.close();
20. out.close();
21.
22. }catch(Exception e){System.out.println(e);}
23. System.out.println("rest of the code");
24. }
25. }
InflaterInputStream class:
The InflaterInputStream class is used to uncompress the file in the deflate compression
format. It provides facility to the other uncompression filters, such as GZIPInputStream
class.
223
19. fin.close();
20. fout.close();
21. in.close();
22.
23. }catch(Exception e){System.out.println(e);}
24. System.out.println("rest of the code");
25. }
26. }
Where it is used
The Reflection API is mainly used in:
Do You Know ?
How
How
How
How
java.lang.Class class
The java.lang.Class class performs mainly two tasks:
224
Description
ClassNotFoundException
InstantiationException,IllegalAccessException
checks if it is interface.
checks if it is array.
checks if it is primitive.
SecurityException
of constructors of this
class.
225
parameterTypes)throws NoSuchMethodException,SecurityException
instance.
226
11. Test t=new Test();
12. t.printName(s);
13. }
14. }
15.
Output:Simple
Let's see the simple example of reflection api to determine the object type.
1. class Simple{}
2. interface My{}
3.
4. class Test{
227
5. public static void main(String args[]){
6.
try{
7.
Class c=Class.forName("Simple");
8.
System.out.println(c.isInterface());
9.
10. Class c2=Class.forName("My");
11. System.out.println(c2.isInterface());
12.
13. }catch(Exception e){System.out.println(e);}
14.
15. }
16. }
newInstance() method
The newInstance() method of Class class and Constructor class is used to create a new
instance of the class.
The newInstance() method of Class class can invoke zero-argument constructor whereas
newInstance() method of Constructor class can invoke any number of arguments. So
Constructor class is preferred over Class class.
228
2. void message(){System.out.println("Hello Java");}
3. }
4.
5. class Test{
6. public static void main(String args[]){
7.
try{
8.
Class c=Class.forName("Simple");
9.
Simple s=(Simple)c.newInstance();
10. s.message();
11.
12. }catch(Exception e){System.out.println(e);}
13.
14. }
15. }
Output:Hello java
229
class Simple{
public static void main(String args[]){
System.out.println("hello java");
}
}
Now let's use the javap tool to disassemble the class file.
1. javap Simple
Output:
1. Compiled from ".java"
2. class Simple {
3.
Simple();
4.
public static void main(java.lang.String[]);
5. }
javap -c command
You can use the javap -c command to see disassembled code. The code that reflects the
java bytecode.
1. javap -c Simple
Output:
1. Compiled from ".java"
2. class Simple {
3.
Simple();
4.
Code:
5.
0: aload_0
6.
1: invokespecial #1
// Method java/lang/Object."<init>":()V
7.
4: return
8.
9.
public static void main(java.lang.String[]);
10.
Code:
11.
0: getstatic
#2
// Field java/lang/System.out:Ljava/io/PrintStream;
12.
3: ldc
#3
// String hello java
13.
5: invokevirtual #4
// Method java/io/PrintStream.println:(Ljava/lang/Strin
g;)V
14.
8: return
15. }
230
Option
Description
-help
-l
-c
-s
-sysinfo
-constants
-version
231
File: A.java
1. public class A {
2.
private void message(){System.out.println("hello java"); }
3. }
File: MethodCall.java
1. import java.lang.reflect.Method;
2. public class MethodCall{
3. public static void main(String[] args)throws Exception{
4.
5.
Class c = Class.forName("A");
6.
Object o= c.newInstance();
7.
Method m =c.getDeclaredMethod("message", null);
8.
m.setAccessible(true);
9.
m.invoke(o, null);
10. }
11. }
Output:hello java
File: A.java
1. class A{
2. private void cube(int n){System.out.println(n*n*n);}
3. }
File: M.java
1. import java.lang.reflect.*;
232
2. class M{
3. public static void main(String args[])throws Exception{
4. Class c=A.class;
5. Object obj=c.newInstance();
6.
7. Method m=c.getDeclaredMethod("cube",new Class[]{int.class});
8. m.setAccessible(true);
9. m.invoke(obj,4);
10. }}
Output:64
Collections in Java
1. Java Collection Framework
2. Hierarchy of Collection Framework
3. Collection interface
4. Iterator interface
Collections in java is a framework that provides an architecture to store and manipulate
the group of objects.
All the operations that you perform on a data such as searching, sorting, insertion,
manipulation, deletion etc. can be performed by Java Collections.
Java Collection simply means a single unit of objects. Java Collection framework provides
many interfaces (Set, List, Queue, Deque etc.) and classes (ArrayList, Vector, LinkedList,
PriorityQueue, HashSet, LinkedHashSet, TreeSet etc).
233
2. Algorithm
Do You Know ?
234
No.
1
Method
public boolean add(Object
Description
is used to insert an element in this collection.
element)
235
c)
invoking collection.
element)
public boolean
removeAll(Collection c)
public boolean
retainAll(Collection c)
element)
public boolean
containsAll(Collection c)
collection.
10
returns an iterator.
11
12
13
element)
14
236
Iterator interface
Iterator interface provides the facility of iterating the elements in forward direction only.
uses a dynamic array for storing the elements.It extends AbstractList class and
implements List interface.
can contain duplicate elements.
maintains insertion order.
not synchronized.
random access because array works at the index basis.
manipulation slow because a lot of shifting needs to be occurred if any element is
removed from the array list.
237
238
Vijay
Ravi
Ajay
239
5.
Student s1=new Student(101,"Sonoo",23);
6.
Student s2=new Student(102,"Ravi",21);
7.
Student s2=new Student(103,"Hanumat",25);
8.
9.
ArrayList<Student> al=new ArrayList<Student>();//creating arraylist
10. al.add(s1);//adding Student class object
11. al.add(s2);
12. al.add(s3);
13.
14. Iterator itr=al.iterator();
15. //traversing elements of ArrayList object
16. while(itr.hasNext()){
17.
Student st=(Student)itr.next();
18.
System.out.println(st.rollno+" "+st.name+" "+st.age);
19. }
20. }
21. }
Test it Now
101 Sonoo 23
102 Ravi 21
103 Hanumat 25
240
Ajay
Sonoo
Hanumat
241
12. al2.add("Hanumat");
13.
14. al.retainAll(al2);
15.
16. System.out.println("iterating the elements after retaining the elements of al2...");
17. Iterator itr=al.iterator();
18. while(itr.hasNext()){
19. System.out.println(itr.next());
20. }
21. }
22. }
Test it Now
iterating the elements after retaining the elements of al2...
Ravi
LinkedList class:
uses doubly linked list to store the elements. It extends the AbstractList class and
implements List and Deque interfaces.
can contain duplicate elements.
maintains insertion order.
not synchronized.
No random access.
manipulation fast because no shifting needs to be occurred.
can be used as list, stack or queue.
Example of LinkedList:
1. import java.util.*;
2. public class TestCollection7{
3. public static void main(String args[]){
4.
5.
LinkedList<String> al=new LinkedList<String>();
6.
al.add("Ravi");
7.
al.add("Vijay");
8.
al.add("Ravi");
9.
al.add("Ajay");
10.
11. Iterator<String> itr=al.iterator();
242
12. while(itr.hasNext()){
13. System.out.println(itr.next());
14. }
15. }
16. }
Test it Now
Output:Ravi
Vijay
Ravi
Ajay
List Interface:
List Interface is the subinterface of Collection.It contains methods to insert and delete
elements in index basis.It is a factory of ListIterator interface.
public
public
public
public
public
public
public
ListIterator Interface:
ListIterator Interface is used to traverse the element in backward and forward direction.
public
public
public
public
boolean hasNext();
Object next();
boolean hasPrevious();
Object previous();
243
4.
5. ArrayList<String> al=new ArrayList<String>();
6. al.add("Amit");
7. al.add("Vijay");
8. al.add("Kumar");
9. al.add(1,"Sachin");
10.
11. System.out.println("element at 2nd position: "+al.get(2));
12.
13. ListIterator<String> itr=al.listIterator();
14.
15. System.out.println("traversing elements in forward direction...");
16. while(itr.hasNext()){
17. System.out.println(itr.next());
18. }
19.
20.
21. System.out.println("traversing elements in backward direction...");
22. while(itr.hasPrevious()){
23. System.out.println(itr.previous());
24. }
25. }
26. }
Test it Now
Output:element at 2nd position: Vijay
traversing elements in forward direction...
Amit
Sachin
Vijay
Kumar
traversing elements in backward direction...
Kumar
Vijay
Sachin
Amit
244
HashSet class:
uses hashtable to store the elements.It extends AbstractSet class and implements
Set interface.
contains unique elements only.
245
16. }
Test it Now
Output:Ajay
Vijay
Ravi
LinkedHashSet class:
contains unique elements only like HashSet. It extends HashSet class and
implements Set interface.
maintains insertion order.
246
TreeSet class:
contains unique elements only like HashSet. The TreeSet class implements
NavigableSet interface that extends the SortedSet interface.
maintains ascending order.
247
248
Vijay
Queue Interface:
The Queue interface basically orders the element in FIFO(First In First Out)manner.
public
public
public
public
public
public
boolean add(object);
boolean offer(object);
remove();
poll();
element();
peek();
PriorityQueue class:
The PriorityQueue class provides the facility of using queue. But it does not orders the
elements in FIFO manner.
Example of PriorityQueue:
1. import java.util.*;
2. class TestCollection12{
3. public static void main(String args[]){
4.
5. PriorityQueue<String> queue=new PriorityQueue<String>();
6. queue.add("Amit");
7. queue.add("Vijay");
8. queue.add("Karan");
9. queue.add("Jai");
10. queue.add("Rahul");
11.
12. System.out.println("head:"+queue.element());
13. System.out.println("head:"+queue.peek());
14.
15. System.out.println("iterating the queue elements:");
16. Iterator itr=queue.iterator();
17. while(itr.hasNext()){
18. System.out.println(itr.next());
19. }
20.
21. queue.remove();
22. queue.poll();
23.
24. System.out.println("after removing two elements:");
249
25. Iterator<String> itr2=queue.iterator();
26. while(itr2.hasNext()){
27. System.out.println(itr2.next());
28. }
29.
30. }
31. }
Test it Now
Output:head:Amit
head:Amit
iterating the queue elements:
Amit
Jai
Karan
Vijay
Rahul
after removing two elements:
Karan
Rahul
Vijay
250
251
records of a table.
252
To connect java application with the Oracle database ojdbc14.jar file is required to be
loaded.
253
2) set classpath:
There are two ways to set the classpath:
temporary
permanent
254
3. Username: The default username for the mysql database is root.
4. Password: Password is given by the user at the time of installing the mysql
database. In this example, we are going to use root as the password.
Let's first create a table in the mysql database, but before creating table, we need to create
database first.
1. create database sonoo;
2. use sonoo;
3. create table emp(id int(10),name varchar(40),age int(3));
255
To connect java application with the mysql database mysqlconnector.jar file is required to
be loaded.
2) set classpath:
There are two ways to set the classpath:
temporary
permament
Enum
An enum is a data type which contains fixed set of constants. It can be used for days of the
week (SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY and SATURDAY) ,
directions (NORTH, SOUTH, EAST and WEST) etc. The enum constants are static and final
implicitely. It is available from Java 5. Enums can be thought of as classes that have fixed
set of constants.
256
1.
2.
3.
4.
5.
257
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35. }
{
super(s, i);
}
public static EnumExample1$Season[] values()
{
return (EnumExample1$Season[])$VALUES.clone();
}
public static EnumExample1$Season valueOf(String s)
{
return (EnumExample1$Season)Enum.valueOf(EnumExample1$Season, s);
}
public static final EnumExample1$Season WINTER;
public static final EnumExample1$Season SPRING;
public static final EnumExample1$Season SUMMER;
public static final EnumExample1$Season FALL;
private static final EnumExample1$Season $VALUES[];
static
{
WINTER = new EnumExample1$Season("WINTER", 0);
SPRING = new EnumExample1$Season("SPRING", 1);
SUMMER = new EnumExample1$Season("SUMMER", 2);
FALL = new EnumExample1$Season("FALL", 3);
$VALUES = (new EnumExample1$Season[] {
WINTER, SPRING, SUMMER, FALL
});
}
Defining enum:
The enum can be defined within or outside the class because it is similar to a class.
258
Output:WINTER
class EnumExample3{
enum Season { WINTER, SPRING, SUMMER, FALL; }//semicolon(;) is optional here
public static void main(String[] args) {
Season s=Season.WINTER;//enum type is required to access WINTER
System.out.println(s);
}}
Test it Now
Output:WINTER
259
enum Season{
WINTER(10),SUMMER(20);
private int value;
Season(int value){
this.value=value;
}
}
260
Java Annotations
261
Java Annotation is a tag that represents the metadata i.e. attached with class, interface,
methods or fields to indicate some additional information which can be used by java
compiler and JVM.
Annotations in java are used to provide additional information, so it is an alternative option
for XML and java marker interfaces.
First, we will learn some built-in annotations then we will move on creating and using
custom annotations.
@Override
@SuppressWarnings
@Deprecated
@Target
@Retention
@Inherited
@Documented
@Override
@Override annotation assures that the subclass method is overriding the parent class
method. If it is not so, compile time error occurs.
262
Sometimes, we does the silly mistake such as spelling mistakes etc. So, it is better to mark
@Override annotation that provides assurity that method is overridden.
1. class Animal{
2. void eatSomething(){System.out.println("eating something");}
3. }
4.
5. class Dog extends Animal{
6. @Override
7. void eatsomething(){System.out.println("eating foods");}//should be eatSomething
8. }
9.
10. class TestAnnotation1{
11. public static void main(String args[]){
12. Animal a=new Dog();
13. a.eatSomething();
14. }}
Test it Now
Output:Comple Time Error
@SuppressWarnings
@SuppressWarnings annotation: is used to suppress warnings issued by the compiler.
1. import java.util.*;
2. class TestAnnotation2{
3. @SuppressWarnings("unchecked")
4. public static void main(String args[]){
5.
6. ArrayList<String> list=new ArrayList<String>();
7. list.add("sonoo");
8. list.add("vimal");
9. list.add("ratan");
10.
11. for(Object obj:list)
12. System.out.println(obj);
13.
14. }}
Test it Now
Now no warning at compile time.
If you remove the @SuppressWarnings("unchecked") annotation, it will show warning at
compile time because we are using non-generic collection.
263
@Deprecated
@Deprecated annoation marks that this method is deprecated so compiler prints warning. It
informs user that it may be removed in the future versions. So, it is better not to use such
methods.
1. class A{
2. void m(){System.out.println("hello m");}
3.
4. @Deprecated
5. void n(){System.out.println("hello n");}
6. }
7.
8. class TestAnnotation3{
9. public static void main(String args[]){
10.
11. A a=new A();
12. a.n();
13. }}
Test it Now
At Compile Time:
Note: Test.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
At Runtime:
hello n
Custom Annotation
To create and use custom java annotation, visit the next page.
264
265
of naming identifiers. Class names, method names and variable names are known as
identifiers. They serve the purpose of representing elements in our program. When those
elements
are
required,
we
refer
to
them
by
their
names.
Following
are
the
rules
to
be
followed
while
naming
identifiers:
1. Identifiers may contain uppercase letters A-Z, lowercase letters a-z and the digits 0-9
2. The only allowed special characters are dollar $ and underscore _
3.
An
identifier
should
not
begin
with
a
number
4.
Spaces
should
not
be
used
5.
Keywords
cannot
be
used
as
identifiers
Keywords are reserved words in a programming language. They have special meanings.
The keywords which we have come across till now are 'public' and 'class'.
Next, we see an open brace { and its corresponding closing brace } can be seen in the last
line. Braces group things together. The braces here indicate that all of the code that
appears
within
it
is
a
part
of
the
class
HelloWorld.
Next we have the method declaration for the method 'main'. Every program which needs to
be run should have a main method. However, if a class is meant only to be used in other
programs and has no need to be run, it need not have a main method.
Just like a class declaration, a method declaration also has several parts. The first is the
keyword 'public', which is an access specifier. The next word 'static' is a keyword which is
used to tell that this method is accessible without creating an object of this class. That is the
reason why this particular method (main) is invoked directly when we run the program even
without creating an object. The next keyword is 'void'. Void states that this method does not
return any value. We shall see more about it later on. The next word 'main' is an identifier.
Just as we have named our class as HelloWorld, we have named our method as main. We
can use any name for a method, but if it is the one to be invoked when the program is run, it
should always be named as main with the specifiers public, static and void. Next we have a
pair of parentheses in which 'String args []' is written. 'String [] args' can also be written as
'String args []'. The square brackets can be placed either after the word String or the word
args. These are known as parameters. We shall look into them later on. Here again, we
have a pair of braces. These again indicate that the code that follows is a part of the method
main.
In this method, we have a single statement. Note that all statements in Java are terminated
by a semicolon. However, class and method declarations are not. This statement is used for
printing on the screen. System is a predefined class just like our HelloWorld class. 'out' is a
266
variable in that class which stores an object. Variables store information which can also be
objects. And print is a method of that class just like the method main in this class. Note that
a dot is used to refer to elements in a sequence just as a / separates the different parts in a
URL. We have accessed the member out of the class System without creating an object.
The reason is that out is defined as a static member. We shall see later on how objects are
created. And to invoke a method, we follow the method name by parentheses and the
required parameters are passed in it. Parameters are those values which are required by
the method to perform its task. The method println () prints something on the screen but it
needs to know what exactly it needs to print. This is passed as a parameter. Note that the
sentence which we pass should be enclosed in double quotes. This is known as a String - a
sequence
of
characters.
When we run this program, the text "Hello World" is displayed on the screen. Change "Hello
World!" in the program to something else and it will be displayed on the screen.
So, in conclusion, when we wish to write a program, its structure should look in the following
way:
public class <class name> {
public static void main(String[] args) {
<statements>
}
}
Replace <class name> with the name that you wish to give to your program or class and
replace statements with those required to perform the task. Everything else remains the
same for simple and small programs. At this point of time, it would be helpful to know a few
things. The first is that Java is a case sensitive language. Uppercase and lowercase letters
are different. Change public in the first line of the program to Public and compile the
program. You will be receiving compilation errors. There is no need to panic about
remembering the case in which different parts of the program are to be written. All keywords
are written in lower case and identifiers such as System (a predefined class) follow certain
conventions
which
we
shall
see
later
on.
And another thing is that Java is a free form language. You can write your program in as
many lines as you want. For example you could have written the first line of the program as
public
class
HelloWorld
{
267
The program still works! However, you can't split single words. For example, you can't write
'cla' on one line and 'ss' on the second line in the following way and expect the program to
compile.
cla
ss
We can state a simple rule that in place of a single space, we can insert as many spaces or
even a new line. And moreover, we can insert spaces and new lines before and after
separators. We have the following separators in Java . , ; { } [ ] ( )
We could have written the System.out.println() statement as:
System
.
out .
println (
"Hello World!";
)
;
However, here again "Hello World!" should be written on a single line. Strings in Java
should begin and end on the same line.
268
A variable has a name, a value and a data type. A variable name is a symbolic
representation of the memory area in which the information would be stored. The value is
the actual data that is going to be stored. And a particular variable can only store one type
of information. It could either be an integer, a real number, a single character or a String.
This
is
specified
by
the
data
type.
In our example, we have a variable named firstNumber of type int and having a value 3. The
data type int is used to store integer values i.e. positive numbers, zero or negative
numbers.
In java we have primitive and reference data types. Primitive data types are the basic data
types which are not composed of any other data types while reference data types are those
which are composed of other data types. Reference data types may be classes or arrays.
We have already seen what a class is. We shall see later on how to create object from
these classes and assign their reference to a variable. Arrays are used to store groups of
data all of which have the same data type. We shall see more about arrays in a dedicated
chapter later on. The term reference also has the implication of being passed by reference,
which
too
which
be
looked
at
in
a
later
chapter.
For now, we will learn about the primitive data types. Java has eight primitive data types,
each of which is capable of storing a particular kind of information. In addition, each of them
also has a range of values which can be stored. Values outside this range cannot be stored
in a variable of that particular data type. The different data types, the amount of memory
required by them and the range of values which can be stored are specified in the table
below.
Data
type
Size in bits
Range ( in exponential
notation)
byte
- 128 to 127
- 27 to 27-1
short
16
- 32 768 to 32 767
- 215 to 215 -1
int
32
- 231 to 231 -1
long
64
- 263 to 263 -1
float
32
-3.4*10-38 to 3.4*1038
double
64
-1.7*10-308 to 1.7*10308
char
16
0 to 65536
boolean
Not properly
defined
We generally use the int data type for storing integers, the double data type for storing real
269
numbers which have a decimal or a fractional part, the boolean data type is used if the
stored values can be either true or false, yes or no, 0 or 1 and other similar pairs and finally
the char data type is used to store a single character.
270
The equal to sign ( = ) is known as the assignment operator. It assigns the value on the
right to a variable on the left. In this case, the value on the right, 3 is assigned to the
variable firstNumber which is stated on the left. The right hand side can also be an
expression. We will look at expressions shortly when dealing with the variable result. Now,
the variable secondNumber is initialised in the following way.
secondNumber = 4;
As already said, declaration and initialisation may be combined in the following way.
int firstNumber = 3; int secondNumber = 4;
Further, we may combine the declaration and initialisation of these three variables into a
single statement as all the three variables have the same data type.
int firstNumber = 3 , secondNumber = 4 , result;
It is to be noted that a variable cannot be declared more than once. If done so, a
compilation error would occur. Also, a variable can't be initialised without first declaring it.
Next, we need to assign the sum of the two numbers to the variable result. Here again, we
assign the result in the same way as we have done for the two numbers. But here, we do
not assign a number such as 3 or 4 but instead we add the two numbers. This results in an
expression. An expression is a combination of operators and operands. Operators are of
different types but for now, we shall be concerned about the mathematical operators +, -, * ,
/ and %. These have the same meaning as in mathematics. The last operator % is known
as the modulus operator which is used to find the remainder when dividing two numbers.
So, the statement for assigning a value to result would like
result = firstNumber + secondNumber ;
This initialisation could be combined with variable declaration in the following way.
int result = firstNumber + secondNumber ;
We could have done this assignment along with the assignment for firstNumber and
secondNumber in the following way but this isn't recommended.
int firstNumber = 3 , secondNumber = 4 , result= firstNumber + secondNumber;
It is always suggested that direct initialisation of variables be separated from the ones
where computation is required. And further, list all variables be listed on separate lines and
not grouped as shown above. Though either of the two ways is correct, we should try to
make
the
code
more
readable.
271
Lastly we need to print the result. For this, we use the println() statement in the following
way.
System.out.println ( "The result of adding "+ firstNumber + " and "+ secondNumber + " is "+
result );
Here, the plus sign acts as a concatenation operator. Concatenation refers to joining two
things. Here, we have joined different Strings and the variables. Wherever, the variable
name appears, it is substituted by its value. So firstNumber would be replaced with 3,
secondNumber by 4 and result by 7. Therefore, the following statement would be printed on
the screen.
The result of adding 3 and 4 is 7
Now, here is the final program for addition.
public class Addition {
public static void main (String args[] ) {
int firstNumber = 3;
int secondNumber = 4;
int result = firstNumber + secondNumber ;
System.out.println ( "The result of adding "+ firstNumber + " and "+ secondNumber + " is
"+ result );
}
}
Storing integers
In the previous example, we have used the int data type to store integers. We may also use
the byte, short and the long data types to store integers depending on the maximum or the
minimum values that are going to be stored. Following statements initialise four variables of
different data tapes with integer values.
byte b = 3;
short c = 4;
int a = 34;
long d = 7L;
272
There is a need to mention how long integers are assigned to variables. An uppercase l or a
lowercase L should be appended to the end of the integer that is going to be stored. This is
because all integers are assumed to be of type int, unless specified as long. However, we
did not append anything to a byte or a short integer. This is because of implicit casting.
Casting refers to converting from one data type to another. 3 was automatically casted from
int to byte and similar was the case with short. In the case of long integers, we need the l to
specify that it is a long integer. if we omit the L at the end of 7 and compile the program, no
compilation errors would be generated. Now, change the value of 7 to something that can
be stored in a long variable but not an int variable and see what happens. A compilation
errors is generated!
long d = 10147483648;
This happens because, the number on the right is too big for an int. Whenever an integers
value if encountered in a program, it is considered as an int value. In the case of byte and
short, the numbers 3 and 4 are initially considered to be of type int but since they are
assigned to some other data type, they have been implicitly cast into byte and short
respectively. In the case of the long integer ( 7L ), we have specified that 7 is a long integer
using the letter L. This long integer was assigned to a long variable. If we had written 'long d
= 7;', the integer 7 is first taken as an int and then implicitly cast to long. In the case of the
number 10147483648, it is initially taken as an int value. But since 10147483648 is too long
for
an
int,
a
compilation
error
occurs.
When we wish to store the result of an expression in a byte or short, the result needs to be
explicitly cast to the corresponding data type. Following is the syntax for casting
( data type ) < variable, literal, or expression >
For example
byte a = 3;
byte b = 4;
byte c = ( byte ) ( a+b );
Note that a+b is written within parentheses. This is because, cast is applied on the variable,
or a literal immediately following the cast data type. To apply it on an expression, the
parentheses is required. ( A literal is a constant data item unlike a variable, such as 3 or 4).
In an arithmetic expression, bytes and shorts are converted to ints before performing any
operation using theose values. Therfore, a and b was first implicitly converted to an int, the
resulting int should be explictly cast to a byte.
273
Real numbers are those which have a fractional part i.e. a decimal part. Real numbers are
also known as floating point numbers. All real numbers are assumed to be of type double by
default. To store a real number in a float variable, an uppercase F or a lowercase f needs to
be appended at the end of the number.
float a = 3.4f;
float b = 34.7F;
double c = 64.7;
We generally use the double data type and not float. We may also represent the numbers in
exponential notation. A number A*10B is written is exponential notation as AeB or AEB.
Either an uppercase e or a lowercase E may be used. The number A is called the mantissa
and the number B is called the exponent. Both of them may be either positive or negative.
The following three statements are equivalent.
double a = 347.347;
double a = 3.47347E2;
double a = 3.47347e2;
274
particular variable. For example, the number 65 corresponds to uppercase A. so, the
following statement is equivalent to the above declaration.
char x = 65;
Note that we do not enclose these numbers in single quotes. This correspondence between
a number code and the graphic character is given by the Unicode. A small subset of these
codes is the ASCII codes which contains numbers between 0 and 127 ( both inclusive) the
ASCII
contains
the
most
commonly
used
symbols.
Following is a list of some of the most commonly used characters and their numeric
representation in either the Unicode or the ASCII code.
Characters
ASCII / Unicode
0-9
48 - 57
a-z
97 - 122
A-Z
65 - 90
275
276
Expressions within the parentheses are evaluated from left to right. In the first println()
statement, both a and b are integers. Hence, they are added together and the result 7 is
displayed. In the second statement, the Strings "3" and "4" were joined by a + sign. It is to
be noted that, here 3 and 4 are Strings and not integers. In the third line, the empty String,
represented by the opening and closing quotes is added to the integer 3. Since a String was
added to the integer 3, the resultant value is a String "3" and not the integer 3. Next this
String is added to the integer 4. Therefore, the integer 4 is converted to the String "4" and
concatenated with the String "3" to give the String "34". In the fourth statement, starting
from the left as usual, we have the integers 3, 4 and a connected with a + sign. Hence, they
are all added to give 10, an integer. Now this integer is added to a String " " giving the
String "10 "and continuing in similar manner, we get the result "10 43". In a similar way, the
277
next statement gives the answer "Result: 34". In the last statement, parentheses have been
used to alter the order in which evaluation is performed. First, the expression within the
parentheses is evaluated. Hence, a + b is evaluated to give an integer 7, which is
concatenated with the String "Result: " to give the final String "Result: 7".
Printing characters
Whenever a char variable is passed as a parameter to the print() or println() methods, the
graphic representation is printed and not the numeric value. It does matter whether we have
initialised the char with a number or with a graphic symbol.
char a=65;
char b='A';
System.out.println(a);
System.out.println(b);
The output would be
A
A
If we want the numeric representation to be printed, we need to cast the variable into one of
the four integer types.
System.out.println((int)a);
The output would be
65
When an integer is added to a char, the char is implicitly casted to an integer.
System.out.println(b+1);
The output would be
66
278
279
other arguments whose number depends on the format String. The format String is similar
to a normal String with the exception that it contains placeholders where appropriate data
items may be placed. These place holders state the type of data that is going to be placed
and also include any other necessary formatting details such as the number of decimal
digits to be displayed, the alignment of the text and so on. For example, consider the
following two equivalent statements assuming that the variable str holds the String "Java":
System.out.println ("Welcome to "+str);
System.out.printf ("Welcome to %s", str);
Both of the above statements print the String "Welcome to Java". However, the approach
taken varies. In the first statement, we have used concatenation while in the second case,
we have achieved the same result by inserting a placeholder for a String (%s) and then
stating the String that needs to be placed in that defined area. We may specify as many
placeholders as we wish and then state their values as arguments in the same order in
which they need to be placed in the empty placeholders. The first parameter in the printf()
method call is known as the format string. And the '%s' and any other similar entities are
known as format specifiers. The digit that follows the % sign ( in this case, an s) is known as
the conversion character. Format specifiers are provided with additional information
depending on the formatting that we wish to apply. Different format specifiers are used to
print different types of text. The table below summarises the most commonly used.
Format specifier
Description
%d
%f
%e or %E
%c or %C
Display characters
%s or %S
Display Strings
%b or %B
%%
Display a % sign
Therefore, to print a short, byte, int or long data item, we use the %d format specifier. To
print float and double values, we use either %f or %e depending on the requirement of
output. To print boolean, char and String data items, we use %b, %c and %s specifiers
respectively.
The following code fragment shows the usage of these specifiers.
int day = 9;
String month = "March";
int year = 1993;
280
char grade='A';
int marks=99;
System.out.format("Born on %dth %s, %d\n", day,month,year);
System.out.format("Secured %d%% marks and %c grade", marks,grade);
The output would be:
Born on 9th March, 1993
Secured 99% marks and A grade
Note how %% was used to display a % sign. If we had simply written % to display a present
sign, it would have resulted in a compilation error. This is because a % sign needs to be
followed by a valid conversion character.
When we need to display data in the form of a table, the task might become cumbersome if
we manually insert the appropriate number of spaces to align the rows properly. For this
purpose, we can use the formatting capabilities provided by this method. The length of the
area in which the text is to be printed is known as the field width. We can specify the field
width by inserting a number between the % sign and the conversion character. If the data to
be printed is smaller, then the appropriate number of spaces are inserted and the data is
right justified. To left justify the data, we place a negative sign before the number. Field
width can be specified for printing any data type.
String name1="Sai";
String name2="Gautham";
int marks1=100;
int marks2=99;
System.out.format("%-10s - %4d\n",name1,marks1);
System.out.format("%-10s - %4d\n",name2,marks2);
The output would be
Sai
- 100
Gautham - 99
Note how the Strings were left justified and the integers right justified.
We can also specify the precision of the data to be printed. Precision defines the number of
decimal digits that are to be printed when we use it with a floating point number. Precision is
specified by placing a dot (.) followed by a number indicating the required precision.
System.out.format("%.3f",34.789456);
281
ava comments
Classes and programs written by you are used not just by yourself but by others too. Under
such circumstances, it may happen that certain portions of the code you have written may
not be easily understandable by others. This could be an algorithm that you have used or
an approach that is part of your class design. In order to explain all such aspects to
someone reading your code, Java provides comments. Comments are sentences which are
ignored by the compiler. These comments at times may also be helpful to you too,
especially in big projects where remembering the purpose of every variable and method
might be a difficult task. Java provides three types of comments: single line comments,
multiline comments and documentation comments. We will now see how these comments
can be incorporated in our program by taking the example of our Addition program which
we have written in the beginning of this tutorial.
Single line comments, as implied by the name span over a single line. They start and end
on the same line. Two forward slashes ( // )mark the beginning of a single line comment and
a new line ( obtained by pressing the enter key) marks its end.
int firstNumber = 3; // This is the first number
Multiline comments spread over many lines. They start with /* and end with */
/* This is
a multiline
comment */
Documentation comments start with /** and end with */. These are special types of
comments which are used to document a class. The documentation of a class gives details
about its variables, constructors and methods. We shall look into documentation comments
later on. For now, we shall see how we can use single line and multiline comments to
improve the readability of our program.
/*
This class is used to add
Two numbers
*/
public class Addition {
282
283
284
However, when we have called the print(), println() and printf() methods, we have a pair of
parentheses at the end in which we have written the arguments. Not all methods require
arguments. We shall study more about methods in detail in a later chapter.
In addition to classes, variables and methods, we also have packages, final variables and
interfaces. The naming conventions for them will be stated when we come across them in
our
study.
Note that following conventions is not mandatory. You can name your class as 'helloWorld'
or 'HellOWoRLd' and the program still works. But following the conventions makes your
program looks professional and people going through your program wouldn't face any
difficulties trying to comprehend whether a particular identifier is a variable, a class, an
interface or some other entity.
double
float
long
int
Atleast one operand is an int but neither operand is a float, a double or a long
Consider that we wish to accept two numbers from the user and divide them. Suppose that
285
we store the numbers in num1 and num2, the following expression would not give us the
required output:
double result = num1 / num2;
We cannot follow the technique which we have used for the computation of average. There
is no way by which we can add a decimal point followed by a zero since we are now dealing
with two variables and not constants. The solution lies in casting to a different data type.
Casting refers to the conversion of one data type to another data type. We have already
seen how we cast data when we were discussing about mathematical operation using byte
varaibles. we cast num1 to double and perform the division in the following way.
double result = (double) num1 / num2;
286
The import statement should be the first line in our program. And then as usual we write the
code for our class or program, similar to what we have done earlier.
import java.util.Scanner;
public class Addition {
public static void main(String[] args) {
// some code here
}
}
This is the structure of a class which we are already familiar with. Now, we need to write
some code in the main method to perform the intended task. Before we write the code, let
us look at how information can be passed from the keyboard to our program using the
Scanner class.
Information flows as a stream just like the way water flows through a hose. The System
class which we have used contains two pre-defined streams. One is the output stream (out)
which is connected the console. We have used it in our earlier programs to print information
on the screen. The other stream is the input stream (in) which is by default connected to the
keyboard. We need to obtain the stream and convert the information in that stream into
meaningful data like integers and Strings. The input stream object (in) is accessed by the
statement System.in 'System', as we have already said is a predefined class and 'in' is a
variable in that class which holds a reference to an input stream object. We now use this in
object to create a Scanner object. As we have already said, to create an object from a
class, we use the constructor of that class. The constructor just like methods may require
arguments. Remember that when we have used the print() or println() methods, we have
passed String arguments like 'HelloWorld'. A Scanner constructor requires an input stream
object as an argument. Therefore we pass the in object to the Scanner constructor and
create a Scanner object named s in the following way.
Scanner s = new Scanner ( System.in );
Note that s is an identifier- a variable name just like firstNumber and secondNumber. And
therforore you can give any name that you want. The proper way to access a variable of
another class (here, in) is to refer to its name by specifying the class name followed by a dot
operator and the variable name.
The keyword new is used to create an object. We will learn more about creating objects
later on. If you have understood all that has been stated till now, it's a good thing. If you
haven't, do not bother. Simply remember that the obove statement is used to create a
Scanner object named s.
287
The Scanner class has several methods which are used to take different types of inputs.
They are listed in the table below.
Method
Description
nextByte()
Accept a byte
nextShort()
Accept a short
nextInt()
Accept an int
nextLong()
Accept a long
next()
nextLine()
nextBoolean()
Accept a boolean
nextFloat()
Accept a float
nextDouble()
Accept a double
Suppose, we want to accept an integer and store it in the variable firstNumber, we write the
following statement:
int firstNumber = s.nextInt();
In a similar way, we can accept other data types from the user. The following code shows
the complete program which accepts two numbers from the user and adds them and
displays the result.
import java.util.Scanner;
public class Addition {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Enter first number: ");
int firstNumber = s.nextInt();
System.out.print("Enter second number: ");
int secondNumber = s.nextInt();
int sum = firstNumber + secondNumber;
System.out.println("The result of addition was " + sum);
}
}
Following shows a sample output when we enter the numbers 34 and 43 as input.
Enter first number: 34
Enter second number: 43
The result of addition was 77
288
289
290
which is higher than the preference for + and -. In order to alter the order in which
evaluation is performed, we use parentheses. Change 3.0 to 3 and you will notice that the
average printed would be incorrect. This is because, the three integers marks1, marks2 and
marks3 on addition give an integer and an integer on division with another integer gives
another integer and not a floating point number. In simpler words, an integer on division with
another integer gives the quotient and not the entire result that includes the remainder part
in the form of a decimal part. However, when the expression involves atleast a single
decimal, we get the decimal part of the calculation as well. That is why we have written 3.0
instead of 3. We shall see more about mathematical calculations in the next chapter.
291
successfully build a virtual world. That is what object oriented programming is all aboutsimulating the real world using objects built from classes.
There are three principles of object oriented programming- abstraction, inheritance and
polymorphism. We shall look at them one by one.
Abstraction is the process of representing the essential features of a system without getting
involved with the its complexities. Consider the Car example again. Once you write the 'Car'
class, other people will be able to create Car objects and use them. You need not disclose
to them how you implemented the starting and stopping of the Car. All that you need to tell
them is how those methods can be called. This is what abstraction is all about. Other
people are capable of using your Car class, create Car objects, and call methods such as
startCar() and stopCar(). They are capable of starting and stopping the car without knowing
how it is being done. Complexities have been hidden. Only the essentialities have been
exposed.
The next feature is inheritance. It is the capability of a new class to inherit the variables and
methods of other classes. The new class can define its own variable and methods in
addition to what have been inherited to provide additional capabilities to the new class. It is
similar to how sons and daughters inherit property and can add their own earned property to
the inherited property. If we talk in terms of the Car example, a new class called SuperCar
can be made to inherit from the class Car so that it will have the functionality of starting,
stopping and changinging speed and in addition will be able to perform some special tasks
like flying in the air similar to what we see in Hollywood movies.
The final feature of object oriented programming that is to be discussed is polymorphism.
This is the property by which different objects can react to the same method call or in
simpler terms a message, and still produce the correct output i.e. the desired output. If we
talk in terms of our Car, then we can state the feature of polymorphism as the ability to
change speed to both a numeric value and a fractional value. Different methods in those
classes will handle these calls but still the message that would be passed would be the
same, which is changeSpeed(). The only difference is in the arguments (the information to
be passed). While one call passes 34 as an argument, the other call would pass 34.7 as the
argument. These things might appear trivial for now but you will be able to appreciate these
features later on when we deal with how these features are implemented in Java.
Hoping that you understood what object oriented programming is, we now move on to the
details of how classes are defined in Java. For the rest of our discussion about building
classes, we will focus on building a Student class. A student will be having a name, a roll
number and marks in three subjects. Once the class is built, we should be able to create
Student objects. And there should be methods for finding the total marks, the average of
two students and so on. In the due course of time, we will also see how we can assign the
292
roll numbers automatically to Student objects starting from 1. We shall also explore some of
the other countless possibilities.
293
We may also give a value to it, which would be the default for objects instantiated from this
class. But, we shall do it in a better way using constructors.
< access specifier > < data type > < variable name > = < value > ;
For now, here is the class Student with five variables.
public class Student {
private int rollNumber;
private String name;
private int marks1;
private int marks2;
private int marks3;
}
We have applied the private access specifier to each of the variables. When we do so,
these variables are accessible from within the class only. Any attempts to access them from
outside the class will result in compilation errors. This can be better explained when we
bring objects into the scene. We create Student objects from this class. After doing so, we
cannot directly request access to these variables by using the object name and dot operator
in the following way.
student1.marks1 = 100; // student1 is of type Student
Recall that we have used the dot operator several times earlier in the print() statement. The
dot operator is used to access members of classes and objects. Earlier we have accessed
the out variable of the class System. While now, we are trying to access the marks1
variable of a Student object, student1. This isn't allowed since the marks1 variable was
declared to be a private variable. If the variable was public, such a statement would have
been valid. We shall see later on how we can create the object student1. We shall also see
how these variables can be accessed or modified using get and set methods. Now, we
move on to constructors. Constructors are used to initialise an object. Constructors appear
somewhat similar in syntax to methods but there are a few differences. There are two types
of constructors- default constructors and parameterised constructors. Default constructors
do not accept any parameters while parameterised constructors accept parameters. Recall
that variables stated within the parentheses are referred to as parameters. These
parameters have a data type and a variable name. We shall now first look into how we can
provide a default constructor.
public Student ( ) {
name = null;
rollNumber = -1;
marks1 = -1;
marks2=-1;
294
marks3=-1;
}
The header of a default constructor (the first line) consist of the access specifier and the
constructor name. The constructor's name should be the same as that of the class, which in
this case is 'Student'. Since this is a default constructor that doesn't take any arguments,
the parentheses are left empty. And then, as usual we start a block using an opening curly
brace. We then initialise the variables to some default values. We have initialised the name
to null. A reference data type when initialised to null indicates that the variable doesn't refer
to any object in memory. Recall that String is a reference data type (since it is class). And
we have initialised the remaining integers to -1 to simply indicate that the Student wasn't
initialised with a proper value. You may, if you wish to do so, provide some other default
values. The following default constructor would also be equally fine. But we have used the
null and -1 default values as they reflect the scenario in a biter way.
public Student ( ) {
name = "No name";
rollNumber = 0;
marks1 = 2;
marks2=3;
marks3=10;
}
But, remember that a class cannot have more than one default constructor.
We now move onto to parameterized constructors. Parameterized constructors accept
arguments which are data items that are used to initialise the variables of a class. Following
shows a parameterised constructor for a class where the five variables are initialised with
arguments that would be received by the constructor.
public
Student
(
String
n,
int
rn,
int
m1,
int
m2,
int
m3)
{
name
=
n;
rollNumber
=
rn;
marks1
=
m1;
marks2
=m2;
marks3=
m3;
}
Since this is a parameterised constructor which receives arguments, the required values
have been stated in the parentheses. We state the data type of the required argument and
give a variable name. This particular parameterised constructor was specified with five
parameters. Each of the parameters should be separated by a comma. The body of the
constructor assigns the values received to the instance variables. Suppose we pass the
values "Gautham", 34,97,99,98 to this constructor; then "Gautham" would be stored in n, 34
295
in rn, 97 in m1 and so on. And then because of the statement name =n; name will be
initialised with "Gautham". In a similar manner, the other variables are also initialised with
the values passed to the constructor. We shall see later on how we pass values to a
constructor while creating an object using the new keyword.
We may define more than one constructor for a class. Suppose, we want to provide the
facility where we should be able to create Student object by simply passing the name and
roll number, and assign the marks to 0, we may do it with the help of another constructor as
shown below.
public
Student
(
name
rollNumber
String
n,
int
=
=
rn)
{
n;
rn;
marks1=0;
marks2=0;
marks3=0;
}
The process of providing more than one constructor to a class is known as constructor
overloading. However, there are certain restrictions here which we shall see later on when
dealing with constructor overloading. For now, we have declared the variables and provided
three constructors. Now, let us provide a method which will print the details of a Student. A
method definition would be similar to what we have already seen in our previous programs.
The only difference would be that we will now omit the word static and also remove the
String[] args parameter. Static was used earlier since there was a need for that main
method to be called without crated an object of that class, be it HelloWorld or Addition class.
The parameter String[] args too had a significance there about which we shall later on when
dealing with command line arguments. String[] is a data type just like String and int and args
was a variable name for the argument that would be passed to main. We will deal with them
later on. For now, here is a method printDetails() which prints the details of the Student.
public
void
printDetails()
System.out.println("Roll
Number:
"+
System.out.println("Name:
System.out.println("Marks
in
first
subject:
System.out.println("Marks
in
second
subject:
System.out.println("Marks
in
second
subject:
{
rollNumber);
"+name);
"+marks1);
"+marks2);
"+marks3);
}
This method looks just like a constructor. The difference is that we have a return type and
the name of the method need not be the same as that of the class. The return type here is
void which means that the method will not return any value after execution. We shall see
296
how to implement methods that return values in a few moments and how to use those
returned values.
We have just started with the design of our Student class but it is still not completed. We
haven't provided a means to modify the values of the variables and there are no methods
that print the total marks and average. However, this current version of the Student class is
sufficient to build objects. Here is the first version of our Student class which has five
instance variables; two constructors- one default and two parameterised and lastly a
method to print details about the student.
The default constructor has been slightly modified to give default value for name as "No
name" instead of null.
public
class
Student
private
private
private
private
private
public
name
public
Student
int
String
int
int
int
Student
=
rollNumber
marks1
String n,
name
rollNumber
marks1
int
rollNumber;
name;
marks1;
marks2;
marks3;
)
"No
=
=
rn,
int
m1, int
=
=
=
m2,
{
name";
-1;
-1;
marks2=-1;
marks3=-1;
}
int
marks2
marks3=
public
Student
(
name
rollNumber
String
n,
=
=
int
rn)
m3)
{
n;
rn;
m1;
=m2;
m3;
}
{
n;
rn;
297
marks1=0;
marks2=0;
marks3=0;
}
public
void
System.out.println("Roll
Number:
System.out.println("Name:
System.out.println("Marks
in
first
System.out.println("Marks
in
second
System.out.println("Marks
in
second
printDetails()
"+
subject:
subject:
subject:
{
rollNumber);
"+name);
"+marks1);
"+marks2);
"+marks3);
}
298
The parentheses were left empty since the default constructor does not require any
arguments. However, if we wish to create a Student object by using a parameterised
constructor, then we need to pass the appropriate arguments, separating them with
commas. We can also separate the declaration of the Student variable from the initialisation
with a Student object in the following way.
Student s1; s1 = new Student();
The above two statements are equivalent to the single statement which was earlier used to
create the Student object s1. The following statements use the parameterised constructors
of the Student class to create Student objects. We pass the required arguments by
specifying them in the parentheses.
Student s2 = new Student ( "Sai", 3 ); Student s3 = new Student ( "Gautham" , 4 , 98 , 100,
96);
The constructor that is to be called is decided by matching the argument list with the
parameter lists of the constructors. In the first statement above, we have specified a String
argument and an integer argument. We have a constructor that corresponds to these
arguments. Hence that constructor is invoked, initialising, name to "Sai", rollNumber to 3,
and marks1, marks2 and marks3 to 0. The second constructor call above matches with the
third constructor provided by us which requires five arguments. It is not just the number of
arguments that is tallied for but also the order and type of these parameters. If we had
replaced the first String with an integer value, or exchanged the first String and the last
integer argument as shown below, we would have received a compilation error.
Student s3 = new Student (4 ,96, 98 , 100, "Gautham"); // incorrect
We can provide not just constants but also variables or expressions in the arguments list.
They would be evaluated before the corresponding constructor is called. The third Student
object s3 could have been created in the following way also:
int num = 96 ; Student s3 = new Student ("Gautham" , 4, num, num+2, 48+52);
The Student object that would result from this statement will identical to the one that was
created earlier. Any variables or expressions in the arguments list are evaluated before they
are passed to the constructor.
Now, we have three Student objects. Each one of them has their own copy of the instance
variables which can be modified independently of others. Following is physical
representation of these three objects.
299
Now that we have created the objects, we will look into how the variables and methods of
these objects can be accessed. In order to access a variable or a method, we use the
reference operator (.) in the following way:
s1.printDetails();
The above statement invokes the printDetails() method on the Student object s1. If the
method requires arguments, we state them within the parentheses just as we had done in
the case of parameterised constructors. Variables too are accessed in a similar way, except
that the parentheses are not included. This is what separates the variables from methods
and helps us to distinguish between the two. If the name variable was public we could have
used the following statement to assign a String to the name variables of s1 in the following
way:
s1.name="Ravi";
We can also print these values, as we would have printed a String variable if the variable
was declared as public.
System.out.println("Name is "+ s1.name);
But, for the current objects such access is denied since the variables were declared to be
private which means that the variables are not accessible outside the class.
Now, we have the complete program below which creates three Student objects and
invokes the printDetails() method on each of these objects.
public class StudentTest {
public static void main ( String[] args ) {
Student s1 = new Student () ;
Student s2 = new Student ( "Sai", 3 );
Student s3 = new Student ( "Gautham" , 4 , 98 , 100, 96);
System.out.println("Student s1: ");
s1.printDetails();
System.out.println("\nStudent s2: ");
s2.printDetails();
System.out.println("\nStudent s3: ");
s3.printDetails();
}
}
When we run this program, we get the following output:
300
Student s1:
Roll Number: -1
Name: No name
Marks in first subject: -1
Marks in second subject: -1
Marks in second subject: -1
Student s2:
Roll Number: 3
Name: Sai
Marks in first subject: 0
Marks in second subject: 0
Marks in second subject: 0
Student s3:
Roll Number: 4
Name: Gautham
Marks in first subject: 98
Marks in second subject: 100
Marks in second subject: 96
301
It is a convention to name the setter methods starting with the word 'set' followed by the
variable name that is going to be set. If we wish to set the name for the first Student object
s1 which we have created, we use the following statement:
s1.setName("Ravi");
Now, we shall provide a get method for the variable name. As we have earlier said,
methods are capable of returning values. These values can be of any primitive data type or
reference type like a class. Here, we will be returning a String. The data type that is going to
be returned in specified in the method header instead of the word void. We have used the
word void till now to indicate that a method does not return any value. The get method for
name would be the following:
public String getName() {
return name;
}
The value that is to be returned is specified by using the 'return' keyword. The variable or
value that is to be returned follows the return keyword. We can specify not just a variable
name but also a constant or an expression. the following return statements would also be
equally fine. return "XYZ";
return "Name: "+name;
However, for the current scenario, we require that only the name be returned and not
anything in addition. Also, the return statement should be the last line in a method that
returns a value. Once the return statement is reached, the lines of code that follow the
return statement would not be executed. In this particular case, we cannot write any
statements after the return statement. This is because unreachable code generates
compilation errors. Unreachable code refers to those statements which can never be
executed. Consider the following get method for name.
public String getName() {
return name;
name = "No name";
}
The statement name="No name" is an unreachable statement. This is because, once the
return statement is encountered, the remaining lines of code in that method would be
ignored. Therefore, the above code produces compilation errors. However, in certain
circumstances, we can provide a return statement and also write code following that
statement when we use decision making statements. We will look into it alter on.
302
Now, that we have written a get method, we shall see how we can use it. We can invoked
the getName() method a Student object, and the returned value can be stored in a variable,
can be printed on the screen or can be used for any other purpose.
In the following statement, the value returned by getName is stored in the variable aName.
String aName = s2.getName();
As we have earlier initialised the name of s2 object with "Sai", aName will hold the value
"Sai". We can also directly print the returned value by invoking the method within the
parentheses in the following way:
System.out.println ("Name of s2: "+ s2.getName() );
In a similar way, we can provide get and set methods for all other variables of the class. But
what exactly is the use of these get and set methods? Instead of providing these methods,
we could have simply made the variables public and they could be accessed in the following
way instead of using get and set methods.
s1.name="Ravi";
System.out.println("Name of s1: " +s1.name);
Such a simpler approach would reduce the work of providing a get and a set method for
each of the five variables, greatly reducing coding work. But that isn't the preferred way for
programmers. When data is easily accessible in that way, data isn't secure. One who uses
the class can easily assign the marks1 of a Student with the integer 1000 where in reality,
the maximum marks are 100. In order to restrict access and to check data before it is
assigned to the variables, we provided the get and set methods. We haven't done such
checking for the name variable. We shall see how it can be done for the marks1 variable.
For this purpose, we use decision making statements. We shall see two of them for now:
the if statement and the if else statement. Following is the syntax of the if statement:
if ( condition ) {
// code
}
And here is the syntax for if else statement
if ( condition ) {
// code1
} else {
// code2
}
303
We hope that you are able to guess what the purpose of the above statements is. To make
sure that you've got it right, let's look at them individually. If the condition stated in the
parentheses of the if statement is true, then the code in the block is executed. In a similar
way, for the if else statement, if the condition is true, the first block of code is executed. If
the condition is false, the statements in the else block are executed. As already said, a
block is a set of statements within a pair of curly braces. They indicate the ownership of a
piece of code. Here, the blocks are used to indicate that the code contained in them is a
part of the corresponding if or else statements. If the code which is to written for an if or else
statement has just a single line or a single statement, there is no need to put the braces.
Another important thing is that variables declared within a block are not accessible outside
the block. Here, if we declare a new variable 'var 'in the if block and try to print its value in
the else blocks, we would be getting a compilation error. The same holds true for methods
also. For instance, if we declare a new variable in the setName() method and try to access it
in the getName() method, we would be stopped bay compilation errors. The following code
is erranous.
public void setName ( String n ) {
name = n;
int var = 34;
}
public String getName() {
var = 7; // incorrect var is not known here
return name;
}
Now, it's time to see how these decision making statements can be used to enforce data
validation in the set methods. But before that we need to learn how we can write conditions
in a language that is understandable by the computer. To make it short, we should be able
to tell the computer 'If marks are greater than or equal to zero and less than or equal to 100,
assign the value to the variable marks, else set the marks to zero'. In order to write
conditions, we use relational and logical operators. We have already come across the other
category of operators- mathematical operators and we have used them widely. Now, we
shall see what the relational and logical operators are. Here are some of the operators in
each of the categories that we would be using widely from now onwards.
Relational operators:
> Greater than
< Less than
>= Greater than or equal to
<= less than or equal to
== equal to
304
!= not equal to
Logical operators
&& Logical and
|| Logical or
! Logical not
Relational operators are used to compare the values of two data items- variables or
constants. Each of the variables requires two operands and the result returned would be
either true or false. All of these operators are similar to what we come across in
mathematics; the only difference lies in their representation. Look at the following code to
see how these relational operators work. As already said, the result of a relational operation
is a boolean value: true or false. Hence, we need a boolean variable to store the result.
int a=3, b=4, c=4;
boolean res1 = a>b ; // res1 holds false
boolean res2 = b<10; // res2 holds true
boolean res3 = b>=c; // res3 holds true
boolean res4 = c<=34; // res4 holds true
boolean res5 = b==c ; // res5 holds true
boolean res6 = 3!=a; // res6 holds true
And now, coming to logical operators- we have three of them. 'Logical and' and 'logical or'
require two operands while 'logical not' requires a single operand. The operands in all the
cases are of type boolean and the result obtained is also a boolean. The 'logical operator
and' (&&) returns true when both the operands are true, otherwise returns false. 'Logical or'
(||) returns true when atleast one of the operand is Tue. And lastly 'logical not' (!) returns
true if the operand is false and returns false if the operand is true. The following are the
truth tables of these operators while are helpful in knowing the value of the returned
boolean when the operands values are known.
Logical operator and &&
Operand 1 Operand 2 Result
true true true
true false false
false true false
false false false
Logical operator or ||
Operand 1 Operand 2 Result
true true true
true false true
false true true
false false false
305
306
marks1 = 0;
}
}
We again emphasize on the fact that Java is a free form language. You can break a
statement into two lines at any valid point and also write more than one statement one
single line. If you feel that reading the above code is inconvenient to you, we suggest the
following alternative form.
public void setMarks( int m)
{
if ( m>=0 && m<=100 )
{
marks1 = m;
}
else
{
marks1 = 0;
}
}
Also, in this case, since the if and else blocks contain only a single statement, you can omit
the braces and write the code in the following way:
public void setMarks( int m)
{
if ( m>=0 && m<=100 )
marks1 = m;
else
marks1 = 0;
}
And another remainder regarding eth accessibility of a variable: Variables defined within a
block are accessible in that block only. These conditions are known as the scope and
lifetime of variables. Scope refers to the part of the code in which the variable is accessible
while lifetime refers to the duration for which a variable exits before it is destroyed by
deallocating the memory allotted to it while declaring the variable. If we declare a variable
within the if block, the lifetime ends once we come of if the if block. Any attempt to access
that variable would give an error that the requested variable is not defined. If there is a need
to declare variables inside such blocks and access them even after we move out of the
blocks, then we need to declare these variables before the starting of the block and outside
the block. Following pieces of code shows an incorrect way and a correct way of using such
variables.
307
308
309
} else {
marks3 = 0;
}
}
public int getMarks3() {
return marks3;
}
public double getAverage() {
return (marks1+ marks2 + marks3) / 3.0;
}
public void printDetails() {
System.out.println("Roll Number: " + rollNumber);
System.out.println("Name: " + name);
System.out.println("Marks in first subject: " + marks1);
System.out.println("Marks in second subject: " + marks2);
System.out.println("Marks in second subject: " + marks3);
System.out.println("Average: " + getAverage());
}
}
Go through the above class carefully and note the following points. The conditions
expressions in each of the three methods for setting marks was written in a slightly different
manner. The parentheses used in them were redundant i.e. it would have made no
difference even if the parentheses were omitted. Following are the three different forms we
have used. All of them are equivalent:
m >= 0 && m <= 100
(m >= 0) && (m <= 100)
(m >= 0) && m <= 100
We can also write the condition in the following way
m >= 0 && ( m <= 100)
Also, note how the if else conditions were written. All of the blocks have a single statement.
Therefore, enclosing the single statement in curly braces is optional. Therefore all the three
forms of if else we have written for the different methods are equivalent. If we want to do so,
we may also enclose the else statement in curly braces and leave the if statement without a
pair of curly braces.
310
Another thing is regarding the computation of average. We need to write 3.0 and not 3. If we
write it as 3, then the result will be an integer and the fractional part would be lost. We could
also have written the statement as:
(marks1 + marks2 + marks3) / (double)3;
Note that return keyword in getAverage() method is followed by the above expression and
not a variable as in the other get methods. Variables, constants and expressions can be
returned. Before returning the expression is first evaluated. We can write the getAverage()
method in the following way also:
public double getAverage() {
double average =(marks1 + marks2 + marks3) / 3.0;
return average;
}
Also note that the return type specified in the method header of the getAvearge() method is
double. This type needs to match with the data type of the value being returned.
The expressions have been written in different styles, using parentheses at some places,
omitting them at few other places, using curly braces at some points and so on. This has
been done to show that all the forms of coding are acceptable. However, when you write a
program, use the same style throughout. It makes your program appeal to others.
And given below is the Test program. In this program, we use the second constructor that
accepts a roll number and a name to create the object. And the marks are set using the
different set marks methods. And then we print data; first by invoking printDetails() method
and then by using the different get methods.
The only thing worth mentioning here is the manner in which we have taken the input:
s1.setMarks1(s.nextInt());
This statement is correct. As already said, arguments passed are first evaluated before they
are passed to the method. So s.nextInt() method would be executed and then the integer
would be passed to setMarks1() method.
The following is the StudentTest class.
import java.util.Scanner;
public class StudentTest {
public static void main(String[] args) {
311
312
And here is a sample input where the user enters incorrect details.
Enter name: Sai
Enter roll number: 34
Enter marks1: 100
Enter marks2: -34
Enter marks3: 347
Printing details using printDetails() method:
Roll Number: 34
Name: Sai
Marks in first subject: 100
Marks in second subject: 0
Marks in second subject: 0
Average: 33.333333333333336
Printing details without using printDetails() method:
Name: Sai
Roll Number: 34
Marks1: 100
Marks2: 0
Marks3: 0
Average: 33.333333333333336
313
Now, try creating a Student object using the constructor where all the values all passed in
the following way.
Student s = new Student ( "sai",34,100,-34,347);
Now invoke the printDetails() method. You will see that marks2 and marks3 were not set as
zero but as -34 and 347. The reason is that in the constructor, we have not provided data
validation. We have directly assigned the values. Hence, we need to modify the
constructors and call the set method from the constructors instead of directly assigning the
values. Following is a modified version of the constructor. The name variable can be either
directly initialised or by calling the set method. Either way gives the same result because no
data validation was provided for the name variable. Following is a modified version of the
constructor.
public Student(String n, int rn, int m1, int m2, int m3) {
name = n; setRollNumber(rn);
setMarks1(m1);
setMarks2(m2);
setMarks3(m3);
}
Variable Name
byte
short
int
long
0L
float
0.0f
double
0.0
boolean
false
char
Null
314
To verify this fact, remove all the constructors from the Student class, create an object of
that class and print the information stored in the variables.
public class Student {
private int rollNumber;
private String name;
private int marks1;
private int marks2;
private int marks3;
public void printDetails() {
System.out.println("Roll Number: " + rollNumber);
System.out.println("Name: " + name);
System.out.println("Marks in first subject: " + marks1);
System.out.println("Marks in second subject: " + marks2);
System.out.println("Marks in second subject: " + marks3);
}
}
public class StudentTest {
public static void main ( String[] args ) {
Student s=new Student();
s.printDetails();
}
}
We get the following output:
Roll Number: 0
Name: null
Marks in first subject: 0
Marks in second subject: 0
Marks in second subject: 0
Average: 0.0
As you can see, all the variables were set to 0 or their equivalent. String which is also a
reference type was set to null. (All classes are reference types). When a variable of a class
type is set to null, it means that the variable wasn't initialized.
315
When we provide atleast one constructor to our class, then the compiler no more provides a
constructor. It doesn't matter whether we are providing a no argument constructor or a
parameterised constructor. The following code generates compilation errors since the class
Student has no default constructor and we are trying to create an object using a default
constructor.
class Student {
public Student ( int m ) {
}
}
class StudentTest {
public static void main ( String args[] ) {
Student s=new Student(); // Incorrect
}
}
Also, if we do not initialise any variables in the constructors provided by us, then they too
are set to their default values. This is not the case with local variables (those defined in
methods).
class Student {
int m;
public Student () {
}
}
class StudentTest {
public static void main ( String args[] ) {
Student s=new Student();
System.out.println(s.m);
}
}
The above program prints 0 in the output. This is because any variables that are
uninitialized in the constructor are initialized with their default values. However, as the
following program shows, this default initialisation does not occur with other types of
variables.
316
Access Specifiers
We have quite often been using the access specifiers- public and private. We shall now see
what these access specifiers actually are, to what entities they can be applied and what
access restrictions are imposed by their usage.
But before looking into access specifiers, let us see what packages are. Packages, in a
simple language can be stated to be a group of related classes. They are just like folders on
your computer and the classes within these packages are like the files contained in folders.
Packages help in organising classes. We shall see how to create and use packages later
on. Every class is a part of a single package. When we do not explicitly specify to which
package a class belongs, it is placed in the default package. Before we can use a class
from a package, we need to import either the entire package or that particular class by
using the import statement as we have done when using the Scanner class. Two packages
are implicitly imported into a class. One is the java.lang package and the other is the default
package in which we are working. That was the reason why we were able to use the
Student class in the StudentTest class without importing the Student class. The class String
which we often use to store text is a part of the java.lang package.
Access specifiers are used to control the visibility of members like classes, variables and
methods. There are three access specifiers: public, private and protected. We shall see only
about the public and private access specifiers for now. Protected access specifier comes
into picture when inheritance is implemented. Also, we may leave the access specifier
keyword unspecified just as we had seen when learning about classes in the beginning. For
example, the following class declaration is also valid though no access pacifier is stated.
class Student {
}
In such cases, the default restrictions (also known as the package restrictions) are applied.
Now, we will see what effect these specifiers have on classes, methods and variables.
Before moving further, there is another thing to be noted. A simple program file can contain
more than one class but only one of them should be declared as public. If more than one
class is declared in the same program file, both of them will be considered as different
classes. Or in other words, one class is not said to be contained within the other class. This
317
318
319
}
}
Following table shows what access specifiers may be assigned to different elements. Note
that all four levels may be applied to all elements except classes. Classes may be declared
with only public and private access specifiers
public
private
protected
class
allowed
not allowed
not allowed
allowed
constructor
allowed
allowed
allowed
allowed
variable
allowed
allowed
allowed
allowed
method
allowed
allowed
allowed
allowed
The following table summarises the above said points regarding the accessibility of entities.
We haven't looked into what a subclass is and the accessibility in a subclass. We shall see
about it when we deal with inheritance.
class
subclass
package
outside
private
allowed
not allowed
not allowed
not allowed
protected
allowed
allowed
allowed
not allowed
public
allowed
allowed
allowed
allowed
allowed
not allowed
allowed
not allowed
Instance variables
Instance variables are those that are defined within a class itself and not in any method or
constructor of the class. They are known as instance variables because every instance of
320
the class (object) contains a copy of these variables. The scope of instance variables is
determined by the access specifier that is applied to these variables. We have already seen
about it earlier. The lifetime of these variables is the same as the lifetime of the object to
which it belongs. Object once created do not exist for ever. They are destroyed by the
garbage collector of Java when there are no more reference to that object. We shall see
about Java's automatic garbage collector later on.
Argument variables
These are the variables that are defined in the header oaf constructor or a method. The
scope of these variables is the method or constructor in which they are defined. The lifetime
is limited to the time for which the method keeps executing. Once the method finishes
execution, these variables are destroyed.
Local variables
A local variable is the one that is declared within a method or a constructor (not in the
header). The scope and lifetime are limited to the method itself.
One important distinction between these three types of variables is that access specifiers
can be applied to instance variables only and not to argument or local variables.
In addition to the local variables defined in a method, we also have variables that are
defined in bocks life an if block and an else block. The scope and is the same as that of the
block itself.
321
a= a+1;
System.out.println ( "Value of a after incrementing is "+a);
}
}
The output of this program would be:
Value of x before calling increment() is 3
Value of a before incrementing is 3
Value of a after incrementing is 4
Value of x after calling increment() is 3
As is evident from the output, the value of x has remain unchanged, even though it was
passed as a parameter to the increment() method. (This program contains two static
methods. The method increment() was also specified to be static since only static members
can be accessed by a static method)
And now, we move on to the second program, where we will make use of class Number that
contains a single instance variable x.
class Number {
int x;
}
class CallByReference {
public static void main ( String[] args ) {
Number a = new Number();
a.x=3;
System.out.println("Value of a.x before calling increment() is "+a.x);
increment(a);
System.out.println("Value of a.x after calling increment() is "+a.x);
}
public static void increment(Number n) {
System.out.println("Value of n.x before incrementing x is "+n.x);
n.x=n.x+1;
System.out.println("Value of n.x after incrementing x is "+n.x);
}
}
This program would give the following output
322
323
The concept of call by reference can be better understood if one tries to look into what a
reference actually is and how a variable of a class type is represented. When we declare a
reference type variable, the compiler allocates only space where the memory address of the
object can be stored. The space for the object itself isn't allocated. The space for the object
is allocated at the time of object creation using the new keyword. A variable of reference
type differs from a variable of a primitive type in the way that a primitive type variable holds
the actual data while a reference type variable holds the address of the object which it
refers to and not the actual object.
324
325
value isn't the object itself but is simply the address at which the object is stored. Therefore,
both a and b refer to the same object. Any change made to the object through either of the
variables gets reflected on the other variable also. That is why when we have changed the
value of x through the variable name b to 5, the change was reflected on the value of x
accessed through a. this is because, a and b are simply different names for the same object
in the computers 'memory.
What the new keyword does is that it simply creates an object and returns reference to that
object i.e. the address of that object. we assign this reference ( address) to an appropriate
variable.
We can compare two reference variables using the == relational operator. The result is true
is both the vraibles refer to the same object, otherwise the result is false. Look at the
following code for example:
Number
a
=new
Number
b
=
new
Number
c=b;//
c
also
boolean
result1=
boolean result2= b==c; // true
Number();
Number();
refers
to
a==b;
//
//
the
first
second
second
//
object
object
object
false
Casting
We have already come across casting quite a number of types. In order to help you, we will
now recollect all that we have learnt about casting till now and then learn something in
addition to what you have already learnt.
Casting refers to the conversion of one data type to another. When we cast a particular
variable, the data type of the variable itself is not altered. For example, in the following
code, when we cast, num1 to a double; the variable num1 does not change its data type
from int to double. Instead, a new copy of num1 is made and its data type is changed to
double.
int num1=3, num2=4;
double result = (double) num1 / num2;
Casting is of two types- up casting and down casting. When we cast a variable to a higher
data type it is known as up casting. A higher data type simply indicates that the memory
allocation for that data type is higher. For example, int is a higher data type than short as
the memory allocated for int is 32 bits which is higher than the memory allocated for a short
which is 16 bits. On the other hand, when we cast a variable to a lower data type, it is
known as down casting. When we up cast a variable, no information is lost but while down
casting a variable, information loss might occur. Consider the following example:
326
short a = 347;
int b= 347347;
short c = (short)a;
int d = (short) b;
System.out.println(c);
System.out.println(d);
This code would give the output:
347
19667
As you can see, when an int was cast to a short, data loss had taken place as the number
347347 is too large for a short variable.
Following conversions fall under down casting
byte -> char
short -> byte, char
char -> byte, short
int -> byte, short, char
long -> byte, short, char, int
float -> byte, short, char, int, long
double -> byte, short, char, int, long, float
And the following conversions fall under up casting
byte -> short, int, long, float, double
short -> int, long, float, double
char -> int, long, float, double
int -> long, float, double
long -> float, double
float -> double
327
int a=3;
long b=4;
long c=a+b; // a is implicitly cast to a long
Look at another example below:
char c='A';
int s=1;
If we perform the addition of c and s (c+s), we get an int as a result. This is because c is
implicitly casted to an int. if we try to store the result in a short or a byte variable; we get a
compilation error saying 'possible loss of precision'. Precision here refers to the number of
digits. Therefore the following statement is invalid.
short ans= c+s;
We will have to cast the result of c+s into a short explicitly in the following way.
short ans= (short) (c+s);
Note that we require a parentheses around c+s. this is because the cast operator has a
higher operator precedence than +. To force the addition to occur first, parentheses are
used as shown above.
It is also possible to cast objects from one class type to another class type. We shall look at
it when we deal with inheritance. For now, this is all you need to know about casting.
328
needs to be done is to specify the particular reference type (the class name) wherever we
had earlier specified the data type as int or double.
We shall now look into each of these possibilities and their applications.
The first in queue is to declare an instance variable of a class type. Assume that we have a
Tutor class which would represent a person who would be taking classes for Students and
each Tutor will be taking classes for exactly two Students. So, we need to have two Student
instance variables in a Tutor class in the following way:
public class Tutor {
Student s1,s2;
}
All the things that we have learnt with declaring and initialising variables of simple data
types are applicable here also. And now, we need a constructor for this Tutor class which
will initialise the variables s1 and s2 with two objects that would be passed as arguments.
The constructor would be having the following form.
public Tutor ( Student stu1, Student stu2 ) {
s1 = stu1;
s2 = stu2;
}
We can also have methods that would return Student objects. For example, consider the
following method getS1 which returns the s1 object. note that this method is however not
necessary here as s1 hasn't been declared to be private.
public Student getS1() {
return s1;
}
Note that we have specified the return type to be Student just like int, double and void. And
lastly, we have to deal with referencing the constituents of an object. Suppose that we have
a Tutor object named t. How would we call the print Details() method of s1? It is very much
the same thing that we have been doing now with a little addition.
t.s1.printDetails();
t.s1 gives us access to the first Student's object and then we invoke the print Details()
method on that object. Here is a small class for Tutor and a test program which follows it
which illustrate all that has been told till now.
329
330
Constants or Literals
We have already come across constants a number of times. Constants are those data items
which do not change their value during the execution of a program. For instance, the integer
5, the String "Hello World" are all constants. Constants can be classified into five
categories: Integer constants, character constants, Floating point constants, boolean
constants and String constants. We have already dealt with all these constants when
dealing with data types. The following table shows the various types of constants and the
data types that fall under them.
Type of Constant
Data Types
Integer Constants
Character Constants
char
float, double
Boolean Constants
boolean
String Constants
String
331
Final Variables
We have seen what a variable is and we are also aware of the fact that a variable may be
assigned a new value any number of times. That is the reason it is known as a variable i.e.
something whose values keeps varying and does remains constant. Suppose that we need
to use the value of PI repeatedly in our program correct to ten decimal places. Mentioning
this value each time may not be a viable option. One thing that can be done is to initialise a
variable named pi to its value in the following way in the beginning of the program and use
the variable wherever the variable is required.
double pi = 3.1428571428;
double volume = pi * radius * radius * height;
But such a representation falsely implies that pi is a variable, something contradicting the
fact that everyone is aware of. Moreover, one might erroneously change the value of the
variable pi to a new value.
pi = 4.1458;
To avoid such mishaps, we have another type of variables in Java known as final variables.
The value of such variables once initialised may not be changed later on during the
execution of the program. Final variables are declared using the final modifier in the
following way:
final double pi = 3.1428571428;
If we later on try to modify the value, as we have done earlier, compilation errors occur. So,
marking a variable whose value shouldn't be changed helps it from being modified
accidentally. This value of pi can be used just like any other value. In order to distinguish a
final variable from a non final variable, we name it in all uppercase letters. If the variable
name consist of more than a single word, they are separated by an underscore ( _ ) sign.
This is the naming convention that everyone follows. For example:
double PI = 3.1428571428;
final int NUMBER_OF_TURNS = 34;
Final variables may be declared as either static or non static. However, it doesn't make any
difference since the value of that variable can however not be changed. The only reason
that could be cited for declaring a final variable as non static is to restrict its access only to
objects of that class and avoid it from being accessed without creating its object.
Also, the value of a final variable should be initialised at the time of its declaration itself. For
example, the statements below would result in errors:
332
333
When used with prefix notation, the value of the variable referred to by the operand is first
incremented and then the new value is used in the expression while in postfix notation, the
value of the variable is first used in the expression and then increased. Look at the following
examples:
int x = 34;
int y = ++x;
The value of x is first incremented to 34 and is then assigned to y. Therefore x is now 35
and y is also 35.
int x = 34;
int y = x++;
x is first assigned to y and then incremented by one. Therefore, x becomes 35 while y is
assigned with the value 34.
Similarly, pre decrement and post decrement operators work.
The post fix or pre fix notations do not make a difference when the operators are applied as
a statement by itself in the following way.
int s = 34;
s++; // s is now 35
int s= 34;
++s; // s is now 35
Give n below is an example to illustrate the use of increment and decrement operators:
int a = 3;
int b = a++;
int c = ++a;
int d = --b + ++c * --d - ++a / --d % ++c;
The first statement assigns 3 to the variable a. The second statement assigns the current
value of a i.e. 3 to b and then increments a to 2. The third statement first increments a to 3
and then assigns its value i.e. 3 to c. Now, after the execution of the first three statements,
the values of a, b and c are 3, 1 and 3 respectively.
Increment and decrement operators have a higher precedence than the other mathematical
operators. Hence, they are applied first from left to right in the order in which they occur
unless one of them has been given a higher precedence through the parantheses.
334
The following lines show the step by step application of the increment and decrement
operators.
--b + ++c * b-- - ++a / --b % c++
a=3b=1c=3
0 + ++c * b-- - ++a / --b % c++
a=3b=0c=3
a=3b=0c=3
0 + 4 * b-- - ++a / --b % c++
a=3b=0c=4
a=3b=0c=4
0 + 4 * 0 - ++a / --b % c++
a = 3 b = -1 c = 4
a = 3 b = -1 c = 4
0 + 4 * 0 - 4 / --b % c++
a = 4 b = -1 c = 4
a = 4 b = -1 c = 4
0 + 4 * 0 - 4 / -2 % c++
a = 4 b = -2 c = 4
a = 4 b = -2 c = 4
0 + 4 * 0 - 4 / -2 % 4
a = 4 b = -2 c = 5
Now, the resulting expression is evaluated according to the rules of precedence of
mathematical operators.
0 + ( 4 * 0 ) - 4 / -2 % 4
0 + 0 - ( 4 / -2 ) % 4
0 + 0 - ( -2 % 4 )
(0+0)-2
(0-2)
-2
335
overloading. Constructors or methods can be overloaded only in a way that would allow
calls to these constructors or methods to be resolved i.e. when an overloaded method is
invoked, the compiler should be able to decide which of the overloaded methods is to be
called by checking the arguments. For example consider an overloaded method print()
having two versions. The first of these does not take any arguments while the second one
takes a single argument. A statement like the following is a call to definitely the second
version of the overloaded method which requires a single String argument.
print ( "example");
However, if both the versions of the overloaded methods take a single String argument,
then the call is non resolvable. A statement like the above could be a call to either the first
or to the second version of the method. Therefore, the overloaded methods here would give
compilation errors. In short, it can be stated that overloading of methods or constructors can
be done only if the parameter list varies in atleast one of the following things: number of
arguments, types of arguments or order of arguments. The return types of the overloaded
method doesn't matter.
Methods calls to overloaded versions are resolved by looking at the above stated three
parameters. Following statements shows a few sets of overloaded methods and also
specify if that particular set is allowed in a single class. The reason is also stated in each
case.
Set 1:
public void print()
public void print ( String str)
This set is allowed since the number of arguments differ in the two cases.
Set 2:
public void print ( int a)
public void print ( String s)
This set is also allowed since the type of parameters are different even though the number
of arguments are the same. One of the overloaded versions of print accepts an integer
argument while the other accepts a String argument.
Set 3:
public void print ( int x )
public void print ( int y)
336
This set may appear as acceptable at the first look but it is not. These versions do not differ
in either the number, order or type of arguments. The variable name in the parameter list
doesn't really matter. For example, consider the following call:
print(34);
This might be a call to either the first method or the second method. Hence this set is not
allowed. The ultimate rule to check the validity of overloaded methods is to see if a method
call is resolvable i.e. there should be a one to one correspondence between a method call
and a method. A method call should always point to a single method and there should be no
doubt as to which of the methods would be called.
Set 4:
public void print ( int a, String s)
public void print ( String s, int a )
This set is an acceptable set for overloading the methods since the parameters differ in the
order in which they are specified even though the number and type of parameters is the
same.
Set 5:
public void print ( int a)
public int print ( int a)
The above sets of methods cannot be declared in the same class. As already said, the
return type doesn't matter when deciding the mutual co-existence of overloaded methods.
One might argue that the call can be resolved depending on whether the call requires a
value to be returned. But such an argument isn't valid because, it isn't necessary that a
returned value should always be used in one or the other way. Consider the following
method call.
print(34);
Looking at this call, one can't say that the print() method doesn't return a value. If we had
only the second version of print (the one that returns an int) out of the two stated versions
above, that version would be the one to be called. The returned int would be simply ignored.
In short, values returned by a method need not always be put to use and therefore the
return type isn't checked to verify the validity of overloaded methods. In a similar way, we
can check the extent to which we can overload constructors for a class.
337
The following class contains overloaded versions of the method findVolume(): the first
overloaded version calculates the volume of a cube, the second one calculates the volume
of a cylinder and the third calculates the volume of a cuboid.
class Volume {
public void findVolume ( int s) {
System.out.println ( "Volume of cube is "+ ( s * s * s ) );
}
public void findVolume ( int r, int h ) {
System.out.println ( "Volume of cylinder is "+ ( 3.14 * r * r * h) );
}
public void findVolume ( int l, int b, int h) {
System.out.println ("Volume of cuboid is " + ( l * b * h ) );
}
}
And here is a test class
class VolumeTest {
public static void main(String[] args) {
Volume v=new Volume();
v.findVolume(3);
v.findVolume(3,4);
v.findVolume(3,4,7);
}
}
The output is
Volume of cube is 27
Volume of cylinder is 113.03999999999999
Volume of cuboid is 84
One particular thing is to be noted here. We have always called the method findVolume()
not bothering if the call would be diverted to the method intended for the cube, cylinder or
cuboid. If Java hadn't supported method overloading, there would have been a need to
write different names for each method. Remembering all those names and calling the
correct version might not always be convenient. Method overloading is one of the ways by
which Java implements polymorphism which is the ability to pass the same message and
338
still receive the correct response. In this particular example, the message passed was the
same i.e. findVolume() and the result was the required one in all the three cases.
As already said, when resolving method calls to overloaded methods, the data types of
arguments passed are verified against the data types of the parameters specified in the
parameter list of the methods. This match between the arguments and the parameters need
not be always exact. Automatic type casting takes place if no exact match is found. Casting
always occurs to higher data types. For example, a byte may be cast into an int but an int is
never cast into an int. The former is known as up casting ( casting to higher data types)
while the latter is known as down casting ( casting to lower data types). For instance
consider the following statements:
byte b = 3;
v.findVolume(b);
This particular method call doesn't match with any of the overloaded versions but still the
first version would be called. This is because of automatic type casting. The byte is first cast
to a short and checked if the method call is resolvable. As no match occurs even after
casting to a short, the short is further casted to an int. Now, a match occurs with the first
version of the method and hence the call gets diverted to it.
If in the above example, we had two versions of findVolume() method, which accept a single
parameter as shown below; one of them accepting short and the other an int; the method
call above would call the version that accepts a short. This is because casting takes place in
gradual steps to higher levels. Once a match is found, casting to higher data types is
halted.
findVolume ( short a) // version 1
findVolume ( int a) // version 2
byte a=4;
v.findVolume(a); // version 1 is called and not version 2
There is another rule which determines the method to be called during automatic type
casting: when the method call contains more than one parameter, after casting either of the
arguments, the method calls should match with only on of the overloaded versions.
Otherwise compilation fails. For example, consider that we have the following two versions
of a method print:
public void print ( int a, byte b)
public void print ( byte a, int b)
And we have the following method call
339
byte a=3,b=4;
print(a,b);
No exact match is found for the above method call and the call is not resolvable even after
casting. The reason is that if a is casted to an int and b is left as a byte, then the call would
be to the first version of the method print(). However, if b is cast to an int and a is left as a
byte, the call would be to the second version of the method. There is no reason why either
the variable a or the variable b needs to be casted to an int in preference to the other.
Hence, the call is non resolvable and would generate a compilation error.
Static variables
A variable can be declared as static by using the static keyword in the following way.
static int a;
Such variables can be defined only in a class. The keyword static cannot be used for
variables that would be declared in methods. Further, a static variable is set to its default
340
value. There is no need to explicitly specify it. However, we are free to initialise it with some
other value if we wish to do so.
static int a = 34;
These static members can be accessed through the class as well as through objects
created from the class. Further, there would be only one copy of static variables. All objects
would be sharing the same copy. The following program illustrates the use of static
variables through the use of a class Number which contains a static variable x and a non
static variable y.
public class Number {
static int x; // x will be initialized to its default value 0
int y; // non static variable
341
Static methods
Similar to static variables, we have static functions also. Functions or methods are declared
as static by specifying the static keyword. A static method can be called either using the
class name or the object name. A static function can access only other static members
(variables or methods). Attempting to access non static members will result in errors.
Following program shows the usage of static functions.
public class Number {
static int x = 7;
int y;
public static void a () {
System.out.println ( "static a() ");
}
public void b () {
System.out.println ( "b() ");
}
public static void c () {
System.out.println ( "x is "+x); // static variable a can be accessed
a() ; // static method a() can be accessed
/*
342
this Keyword
The this keyword in Java returns a reference to the object on which the method being
executed is invoked. We can use the returned reference to access the variables and
methods of the object. Look at the following example where the this keyword is used in a
constructor
class Student {
String name;
public Student ( String name ) {
this.name = name;
}
}
343
As we know, a constructor is used to create the object of the class. So, the keyword this
returns a reference to the object being created. Therefore, this.name refers to the instance
variable 'name' which is assigned with the 'name' passed to the constructor. We could have
of course written the constructor as we would have normally written in the following way:
public Student ( String n ) {
name = n; }
But, in this case, a person who is reading the code wouldn't know what n is unless he
continues to the next line. So, the use of this keyword is justified in the constructors of a
class.
The this keyword is also used to access instance variables that have been hidden by local
variables. We have read that a variable can be declared only once. However, there is an
exception to this. We can declare an instance variable and a local variable (for example, a
variable in a method) with the same name. When we use the variable name in the method
body, we get the value which the local variable points at. In effect, the local variable has
hidden the instance variable.
public class Student {
int marks = 34;
public void newMarks () {
int marks = 100;
System.out.println ( marks );
}
}
The method newMarks() in the above program would print the integer 100 and not the
integer 34. This is because the local variable marks has hidden the instance variable marks.
In order the access the hidden variable, we make use of the this keyword in the following
way.
System.out.println ( "Old marks: " + this. Marks ); // prints 34
The this keyword has returned a reference to the object and therefore marks accessed
through the this keyword refers to the marks that was declared as an instance variable.
The this keyword is also used to call one constructor from another. This is quite helpful in
reducing code work when a number of instance variables are declared in a class and there
is a necessity to provide a number of constructors which would be able to create objects of
that class whether all the necessary parameters have been passed or not. In simpler terms,
creation of the object should be made more flexible. The user should be allowed to go
344
ahead, whatever be the information he possesses, be it only the name and rollNumber, just
the rollNumber or all the details. Look at the following example of the Student class.
class Student {
String name;
int rollNumber;
int marks1, marks2, marks3;
public Student ( String name, String rollNumber, int marks1, int marks2, int marks3 ) {
this.name = name;
this. rollNumber = rollNumber;
this.marks1= marks1;
this.marks2 = marks2;
this.marks3= marks3;
}
public Student ( String name, int rollNumber ) {
this ( name, rollNumber, -1,-1, -1 );
}
public Student ( String rollNumber ) {
this ( null, rollNumber );
}
}
When we create an object of the Student class in the following way, the second constructor
would be invoked which would then invoke the first constructor.
Student s= new Student( "Sai", 34);
And, if we use the following statement, all the three constructors would be called in effect.
We are actually making call to the third constructor, which then calls the second which in
turn calls the first.
Student s= new Student (34);
An important thing to be remembered when calling other constructors using the keyword
this, is that such a call should be the first statement in the constructor. The following code,
for instance would result in an error:
public Student () {
System.out.println ("No argument constructor called"); // incorrect
this(-1); }
345
Wrapper Classes
As we have already seen, a variable of primitive data type is by default passed by value and
not by reference. Quite often, there might arise the need to consider such variables of
primitive data type as reference types. The solution to this lies in the wrapper classes
provided by Java. These classes are used to wrap the data in a new object which contains
the value of that variable. This object can then be used in a way similar to how other objects
are used. For example, we wrap the number 34 in an Integer object in the following way:
Integer intObject = new Integer (34);
The Integer class is the wrapper class that has been provided for the int data type. Similarly,
there are wrapper classes for the other data types too. The following table lists the data
types and their corresponding wrapper classes.
Data Type
Wrapper Class
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
char
Character
boolean
Boolean
Note that the wrapper classes of all the primitive data types except int and char have the
same name as that of the data type.
A wrapper class also contains a number of other different methods which may be used in
the processing of variables of the corresponding data type. For example, the Character
wrapper class contains methods which can be used to check if a character is a digit or a
letter or a whitespace and so on.
346
For example, we can create an Integer object which wraps the int 34 in either of the
following two ways:
Integer intObject = new Integer (34);
Integer intObject = new Integer ( "34");
347
have the format parse*() where * refers to any of the primitive data types except char. And
to convert any of the primitive data type value to a String, we use the valueOf() methods of
the String class which through method overloading and implicit casting can accept any of
the eight primitive types.
int x = Integer.parseInt("34"); // x=34
double y = Double.parseDouble("34.7"); // y =34.7
String s1= String.valueOf('a'); // s1="a"
String s2=String.valueOf(true); // s2="true"
Control Statements
All the programs we have written till now had a sequential flow of control i.e. the statements
were executed line by line from the top to bottom in an order. Nowhere were any statements
skipped or a statement executed more than once. We will now look into how this can be
achieved using control structures. These control structures can be classified into three
groups: Decision making statements, repetition statements and branching statements.
Decision making statements are used to decide whether or not a particular statement or a
group of statements should be executed. Repetition statements are used to execute a
statement or a group of statements more than once. Branching statements are used to
transfer control to another line in the code. We shall look into the syntaxes of these
structures first and then see how we formulate algorithms using these statements.
We have already seen the if statement and the if else statement while writing the set
methods for our Student class. The if statement is used to selectively execute a statement
or a block of statements. The if statement contains a condition which decides whether or not
the statements would be executed. If the condition stated in the parentheses evaluates to
true, then the statements are executed, otherwise the statements in the if block are skipped.
Conditions, as we have already seen are built using conditional and relational operators.
Following is the syntax of the if statement.
if ( condition ) {
// code
}
And here is a small code snippet which displays the message "Hi" only if the value of the
boolean variable wish is true.
if ( wish == true ) {
System.out.println("Hi");
}
348
In the above code snippet, the braces could have been omitted. Braces are not required
when the block consists of only a single statement. But we recommend that braces always
be placed. This ensures that mistakes won't creep into the code when you modify your
program at a later time to add another statement to the if block forgetting to insert the
necessary braces. Moreover the condition 'wish==true' could have also been written as
'wish'. Both are equivalent and perform the same condition check.
The if statement is known as a single selection structure since we have only a single
statement that is either executed or not. No alternative statement would be executed if the
condition evaluates to false. For such purpose, we have the if else double selection
structure. If the condition is true, the if block will be executed. Otherwise, the else block will
be executed. Following is the syntax of if else structure.
if ( condition ) {
// code
} else {
// code
}
And here is an example usage which states whether a number is an even number or an odd
number. Even numbers are divisible by zero and hence leave a remainder of zero. The
remainder on dividing the number by two can be obtained using the modulo (%)
mathematical operator.
if ( num%2==0){
System.out.println("Number is even");
}else{
System.out.println("Number is odd");
}
if else statements can be nested. That is the statements block of an if or else can in turn
contain another if else structure. And moreover, an else is always associated with the
immediately preceding else. These two concepts are used to form a chained if else
structure in which only one of the several alternatives is executed. Look at the following
code where if else structures have been nested to print the number stored in the int num in
words when the value of num is between one and three. If the number falls outside this
range, an appropriate message is displayed.
if (num == 1) {
System.out.println("One");
} else {
if (num == 2) {
System.out.println("Two");
349
} else {
if (num == 3) {
System.out.println("Three");
} else {
System.out.println("Numbers greater than three cannot be processed by this code");
}
}
}
This code looks highly unreadable. One thing that we can do is to remove the redundant
braces since each of the blocks contain no more than one statement. You may be hesitant
to perform this action with the first else statement since it contains more than a single line of
code. But all that would still fall under the else statement even if we remove the braces. This
is because the statement within the if block is associated with the if header and the
succeeding else is associated with the if block. So the entire block will be associated with
the else even if no braces are used. So, after we remove the braces, this is what we are left
with. We have also written the words if and else on the same line.
if (num == 1) {
System.out.println("One");
} else if (num == 2) {
System.out.println("Two");
} else if (num == 3) {
System.out.println("Three");
} else {
System.out.println("Numbers greater than three cannot be processed by this code");
}
This code looks much better than the earlier once. This is what we refer to as chained if
else structure formed using a number of if and else statements. Only one out of the four
statements will be executed depending on the value of num. Once a particular statement is
executed, the remaining ones would be ignored. This chained control structure is quite
frequently used.
We could have used a set of four if statements instead of the above chained sequence but
that that code would take a longer time to execute. This is because all the conditions would
be checked. But in this chained structure, one a condition evaluates to true, all other
statements are skipped which would reduce processing time, hence, making the code more
efficient.
As already said, an else is associated with the immediately preceding if. Indenting the code
by using tabs has no effect on how the code works. Assuming that the indentation matters
may lead to errors in programming. Consider the following code:
350
if(x>3)
if(y>3)
System.out.println("Both x and y are greater than 3");
else
System.out.println("x is not greater than 3");
By looking at the indentation one might be tempted to say that the last else is associated to
the first if. But this is erroneous since an else if always associated with the immediately
preceding if unless braces are used to associate the else with a different if. This problem of
which if the final else is to be associated is known as the dangling else problem. If we
wrongfully assume that indentation matters, the result obtained would be incorrect. Include
the above code in a program and set x and y to 2. According to what one might think, the
statement "x is not greater than 3" is not printed. Given below is a corrected version of the
above code.
if(x>3) {
if(y>3)
System.out.println("Both x and y are greater than 3");
} else
System.out.println("x is not greater than 3");
In order to avoid such trivial mistakes, always use braces unless you are writing a chained if
else structure in the case of which using braces makes the code clumsy and hard to
decipher.
Apart from the if and else statements, we have the switch structure. The switch control
structure however cannot be used in the situations where the condition needs to contain
relational operators like greater than, less than and so on. The switch structure can only be
used to check for equality. Given below is the syntax of the switch structure in Java.
switch ( expression )
{
case value1 :
// code
break;
case value2:
// code
break;
...
...
case valueN:
// code
break;
...
351
...
default:
// code
break;
}
The expression should evaluate to one of the following types: byte, short, int, char, String.
This value is compared with each of the case values ( value1, value2,... valueN). When a
match is found, the statements under that particular case label are executed. Strings are
checked for equality by invoking the equals() method and not by using the == operator
which is the used for the other data types. If no match is found, the statements under the
default label are executed. The break keyword is used to transfer control outside the switch
block. If the break keyword is omitted, the statements under the other case labels are also
excited whether or not the case value matches. This might be useful in certain situations
which we will look into shortly. The last break under the default label is optional as on
reaching the line, the control has to anyway move out of the switch block. All the case
values should be unique. Duplicates are not allowed. Also note that braces are not required
even if we wish to include more than one statement in a particular case label. However,
using them doesn't make any difference. Given below is an example which prints the day of
the week based on the value stored in the int variable num. 1 stands for Sunday, 2 for
Monday and so on:
int day = s.nextInt; // s is a Scanner object connected to System.in
String str; // stores the day in words
switch(day)
{
case 1:
str="Sunday";
break;
case 2:
str="Monday";
break;
case 3:
str="Tuesday";
break;
case 4:
str="Wednesday";
break;
case 5:
str="Thursday";
break;
case 6:
str="Friday";
352
break;
case 7:
str="Saturday";
break;
default:
str=" Invalid day";
}
System.out.println(str);
The value stored in day is compared with each of the case values 1 to 7. If a match is
found, the statements under the corresponding case label are executed. And since, break is
encountered, the remainder of the code in the switch structure so skipped. If the value
stored in day does not fall in the range 1-7, the default statement is executed.
As already said, at times, there might be a need to omit the break statement under certain
situations where we want the same set of statements to be executed as a target of more
than a single case label. Look at the following example where the season is printed
deepening on the month.
switch(month)
{
case 12:
case 1:
case 2:
System.out.println(" Winter");
break:
case 3:
case 4:
case 5:
System.out.println(" Spring");
break:
case 6:
case 7:
case 8:
System.out.println(" Summer");
break:
case 9:
case 10:
case 11:
System.out.println(" Autumn");
break:
default:
System.out.println(" Invalid month");
}
353
Suppose we have the value of month as 4. This value would be compared each of the case
values 12 to 4. The value of month equals the case value 4. Therefore statements under
this case label would be executed until a break is encountered. However, note that in the
statements that follow, the value of month is not compared with any of the case values. In
this example, the value of month would not be compared with 5. The next print() statement
is executed. After this, the break statement is encountered because of which, control shifts
outside the switch structure.
The last of the decision making statements is the ternary operator which provides a concise
form for short and simple if lese statements. The ternary operator is represented by ?:
Following is the syntax of ternary operator:
expression1 ? expreession2 : expression3
If expression1 evaluates to true, then expression 2 is evaluated, otherwise expression 3 is
evaluated. The ternary operators can be used as a standalone statement or in conjugation
with other statements like declaration and print statements. Following examples illustrate
the use of ternary operator:
Example 1: The value of s (an int ) is either incremented or decrement based on whether it
is a positive integer or not.
s>0 ? s++ : s-- ;
If s is 3, then s is incremented to 4. If s is 0, it is decremented to -1.
Example 2: Division
If the divisor is zero, then the quotient is set to zero, otherwise division is performed and the
quotient is stored in the variable res. a and b are the dividend and divisor respectively.
int res = b==0 ? 0 : a/b;
if b is zero, then the expression b==0 evaluates to true, hence the first expression is
evaluated. 0 is the result of the ternary operation which is assigned to res.
If b is non zero, expression1 evaluates to true. Hence expression 3 is evaluated i.e. the
ternary operation returns the result of dividing a by b. This returned value is assigned to
num.
Example 3: Ternary operator in print statements
The following statement prints either "Positive "or "Non positive "depending on the value of
num.
354
Repetition Statements
Java provides three repetitions structures: while, do while and for. These statements are
also known as loops. We shall look into the syntaxes of these structures first and also learn
how we can formulate algorithms using these loops.
355
356
ctr++;
}
Always use integers (byte, short, int or long) variables as counters. Never use floating point
numbers to control loops since floating point numbers are not accurate values. For
example, the floating point constants 3.4 is not exactly the value 3.4 but is an approximation
of some other closer value like 3.39999999999.....
Following program shows how the output produces will be incorrect when using floating
point constants. The actual purpose of the program was to print the floating point numbers
0.1, 0.2, 0.3 ....1.0 on the screen but the result produced was different.
double ctr = 0.1;
while (ctr <= 1) {
System.out.println(ctr);
ctr = ctr + 0.1;
}
Output:
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
As you can see, instead of displaying 0.3, 0.30000000000000004 was displayed and similar
is the case with the last three numbers. Similar would have been the case if we used ctr to
print some statement a predefined number of times.
While loop is an entry control loop which means that the condition is checked before
entering the body of the loop. Therefore, it might be possible that the body of the loop is not
executed even once. For example, if we set the condition in the above examples to str<0,
the loop is not executed even once. In contrast, we have the exit control loops in which the
condition is checked after executing the body of the loop because of which the loop is
executed atleast once. Following is the syntax of the do while loop:
357
do {
// code
} while ( condition );
Note that there is a semicolon after the while statement. Following code uses the do while
loop to print "Hi" thrice on the screen.
int ctr = 0;
do {
System.out.println("Hi");
ctr++;
} while (ctr < 3);
The last of the repetition statements is the for loop which provides a more convenient way
to handle counters in loops. Following is the syntax of a for loop:
for ( initialization; condition; increment/ decrement ) {
// body
}
The for header has three parts namely initialisation, condition and increment/ decrement.
The initialisation part is used to declare and initialise loop control variables or any other
necessary variables before entering into the loop. The condition is checked before
executing the loop and the increment/ decrement part is executed after each time the body
of the for loop is executed. The third part of the for header can also contain statements
other than increment and decrement operations. The above for loop is equivalent to the
following while loop.
initialisation;
while ( condition ) {
// body
increment / decrement;
}
However, there is major difference between these two loops. Variables that are declared in
the for header have a scope and lifetime that is limited to the body of the for loop. These
variables are not accessible once we come out of the for loop. This is one reason why for
loops are preferred over while loops.
Following code prints the numbers from 1 to 10 using a for loop.
for ( int i=1; i<=10; i++) {
System.out.println(i);
}
358
We generally use the identifiers I, j, k for loop control variables. We may also, declare these
variables outside the for loop if the value of this counter if required after control moves out
of the for loop.
int i;
for (i=1; i<=10; i++) {
System.out.println(i);
System.out.println("The value of i was "+i +"when the loop condition evaluated to false");
}
The above code will display the statement "The value of i was 11 when the loop condition
evaluated to false" in addition to printing the numbers from 1 to 10. If the variable i was
declared in the for header itself, the above print statement would have produced a
compilation error.
We may declare more than a single variable in the initialisation part of the header. However,
each of these variables should have the same data type and they should have not been
declared earlier. The following for header declares and initialises two variables i and j.
for ( int i= 0, j=10; // code; // code )
Here are the various formats of the initialisation part that are allowed:
< variable name > = <value >
< data type > < variable name > = < value >
< data type > < variable name 1 > = < value (optional) > , < variable name 2 > = < value (
optional ) >, ...... <variable name n > = < value ( optional ).....
The increment decrement part can contain more than one statement. These are separated
by a comma and not by a semicolon. Generally, we use this part only to increment or
decrement variables, though other statements are also allowed.
for ( // code; // code; i++, j++, k+=5 ) {
//code
}
It is not necessary that all the three parts of the for header have to be present. One or all of
them may be skipped. Following shows a for header in which only the condition part is
specified. The other two parts are left empty.
for( ; i<=10; ) {
// code
}
359
In all the above three decision making statements, if the condition is left empty, it is taken as
true. Such a loop keeps executing for ever and is known as an infinite loop.
while ( ) {
// code
}
Infinite loops may also result even after specifying the condition as in the following
example:
for ( int i=1; i <= 10 ;i--) {
System.out.println(i);
}
Infinite loops are considered to be logical errors. There would be no reason as to why a
programmer wishes to run a loop for ever. This would eventually cause the system to crash.
Infinite loops result from trivial mistakes. For example, in the just preceding example, i++
was replaced with i-- which caused the loop to run continuously. Loops that do not have a
body are known as empty loops. For example, the following while loop is an empty loop:
while ( ctr++<10 ) {
}
We may also write this loop in the following way:
while ( ctr++ < 10 ) ;
The above statement is equivalent to the following which contains an empty statement. As
stated already, whitespaces do not matter in a program.
while ( ctr++< 10 )
;
Control statements may be nested within one another. An if else structure may be written
inside a for loop, a for loop can contain another for loop which in turn can contain one more
for loop and so on...
Nested Loops
Nested loops are quite helpful in processing information. We will learn how nested loops are
used by taking the example of a pattern problem. An integer value is to be taken as an input
from the user and the following pattern is to be printed based on the input. If the input is
seven, the following pattern needs to be printed.
360
*
**
***
****
*****
******
*******
One thing that is obvious on observing this pattern is that loops are used to print the pattern.
This is because, we are not aware in advance of the number of *'s that are to be printed.
Further, we need nested loops: a for loop nested within another for loop. the outer for loop
keeps track of the line number. Or, in other words, it is used to count the number of lines we
are printing. The inner for loop is used to keep track of the number of *'s we are printing.
Urther, the number of stars on a particular line is equal to the number line number which in
some way can be realted to the outer loop control variable. keeping these things in mind,
we can write the following code which prints this pattern. The number n is atken as an input
from the user:
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
System.out.print("*");
}
System.out.println();
}
Note that we have used the print() method and not the println() method to display the stars
as we want the *'s to be displayed on the same line. And after the inner loop is executed,
we go to the next line using the println() statement.
Formulating Algorithms
Now that we have learnt about two of the control structures, we shall see how we can
formulate algorithms using theses structures. We do have another group of control
structures- branching statements, about which we shall see later on. We have two basic
approaches, each of which is used for a particular situation. The first is counter controlled
repetition and the other is sentinel controlled repetition. Counter control repetition is
followed when we know in advance the number of times the loop has to be executed while
the sentinel controlled approach is taken when this number is not known before entering the
loop. We will deal with the problem of adding numbers to understand these two
approaches.
361
We have already used controlled repetition when discussing the basics of loops. This
example would make the approach more clear. This is the problem: the number of numbers
to be added is to be first taken as an input. The user is then prompted for the numbers
which will be added by the program. The sum of the numbers entered is then displayed on
the screen. This is the program which performs the task:
import java.util.Scanner;
public class AddNumbers {
public static void main(String args[]) {
Scanner s = new Scanner(System.in);
System.out.print("Enter the number of numbers that you wish to add: ");
int count = s.nextInt();
int sum = 0;
for (int i = 1; i <= count; i++) {
System.out.print("Enter number " + i + ": ");
sum = sum + s.nextInt();
}
System.out.println("The sum of the numbers is " + sum);
}
}
Given below is a sample output:
Enter the number of numbers that you wish to add: 4
Enter number 1: 34
Enter number 2: 7
Enter number 3: 4
Enter number 4: 347
The sum of the numbers is 392
As you can see in the program above, we have taken the count as an input from the user.
The loop is executed these many number of times. A counter, i is used to keep track of the
number of numbers that have been added. Each time, the value of i is also displayed along
with a prompt for the number. Within the for loop itself, the number taken as input is added
to sum.
362
program to stop taking the input. Given below is a program which uses a while loop driven
by a sentinel to calculate the sum of numbers entered by the user.
import java.util.Scanner;
public class AddNumbers {
public static void main(String args[]) {
Scanner s = new Scanner(System.in);
int sum = 0;
int num;
do {
System.out.print("Enter a number (0 to stop): ");
num=s.nextInt();
sum=sum+num;
}while(num!=0);
System.out.println("The sum of the numbers is " + sum);
}
}
And here is a sample output:
Enter a number (0 to stop): 3
Enter a number (0 to stop): 4
Enter a number (0 to stop): 7
Enter a number (0 to stop): 34
Enter a number (0 to stop): 0
The sum of the numbers is 48
Note that we have used a do while loop instead of a while loop or a for loop. We could have
used them also and modified the program accordingly. In this particular program, we are
first adding the number entered by the user to sum and then checking if it is the sentinel.
Since the sentinel is 0, it doesn't make any difference if we add the number first and then
check or check the number and then add it to sum. However, if the sentinel is another value
like -1, then the order does matter. In that case, we can take several approaches. One is to
subtract the sentinel from the sum after coming out of the loop and before displaying the
sum. But this doesn't look quite good and therefore we present below, a few alternate
versions to be used when the sentinel is a value other than 0.
Version 1:
int sum = 0;
int num = 0;
do {
363
Branching Statements
We will now look at the last set of control statements in Java- branching statements. They
are used to transfer control to another point in the code. Java's branching statements are
defined by the three keywords- break, continue and return. The break and continue
statements have two forms: the labelled form and the unlabelled form. We shall now look at
each one of them in detail.
Java's break statement is used to exit out of a loop. We have already seen the use of the
break statement in the switch structure. We shall now see their use in loops. break is
normally executed as a target of a decision making statement like if. Look at the following
for loop which should actually print the integers from one to seven. However, because of the
break statement that is associated with an if, only the numbers up to four are printed. When
the break keyword is encountered, controls gets transferred to the end of the loop and
statements following the loop are executed.
for (int i = 1; i <= 7; i++) {
System.out.println(i);
if (i == 4) {
break;
364
}
}
The above code will print the numbers from 1 to 4, one each one line.
1
2
3
4
When loops are nested within one another, the use of break will causes control to move out
of the loop to which the break statement belongs. Look at the following partial code which
contains three loops nested within one another. The break statement is a part of the second
for loop. On encountering it, control shifts to the line indicated by "// control shifts here".
for ( ..... ) {
for ( ..... ) {
for ( ..... ) {
}
if ( ..... ) {
break;
}
}
// control shifts here
}
In the above program, if on encountering the break statement, we want control to be
transferred to the end of the outermost loop instead of the second loop to which the break
statement is associated by default, we use a labelled break statement. Before using it, we
need to define a label. A label is an identifier followed by a colon. A label is associated to
the loop that is defined immediately after the label. When the break is followed by a label,
encountering it will cause the control to be shifted to the exit of the loop corresponding to
that particular label. Look at the first statement where a label named "here" (Label names
should follow the rules of identifiers), is set to be associated with the outer for loop. When
the break statement is encountered in the for loop, control is transferred to the end of the
outer loop instead of the inner loop as a labelled break has been used.
here:
for ( ..... ) {
for ( ..... ) {
if ( ..... ) {
break here;
}
365
}
// control shifts here on encountering the labelled break
You will be able to appreciate the use of these branching statements when we deal with
arrays. However, for the time being, to help you get familiar with the two forms of break
statement's, we present below an example, with has three for loops nested within one
another. We also have a label for each of these for loops. The code is first executed without
any break or continue statements and then, we introduce several break statements, labelled
and unlabelled and show you the outputs.
public class Break Example {
public static void main(String[] args) {
label1:
for (int i = 1; i <= 3; i++) {
label2:
for (int j = 1; j <= 3; j++) {
label3:
for (int k = 1; k <= 3; k++) {
System.out.print(k);
// line1
}
System.out.println();
//line2
}
System.out.println();
//line3
}
}
}
And here is a table. Use it to manipulate the above code by replacing line1, line2 and line3
with the contents of this table. Run your program and match your results with the ones
shown here. Reason out for yourself the logic behind the output. Note that in this example,
we haven't executed break statements as a target of a decision making statement to make
the code simpler.
In certain rows of the above table, we have stated //compilation errors. The code in those
cases is incorrect since we are trying to access labels that are not known in those scopes.
For example, when two loops are nester within one another with the outer loop labelled
outer: and the inner loop labelled inner:. Trying to break to inner within the body of the outer
loop will result in a compilation error.
366
outer:
for ( ..... ) {
inner:
for ( ..... ) {
}
break inner; // error
}
You can try out more combinations for the three lines in the above program by including the
break statements on more than a single line. For your reference, 54 combinations are
possible in all, including the above stated ones. A majority of these would result in
compilation errors.
Now we move on to the continue statement. The continue statement just like the break
statement has two forms. When the continue statement is encountered, the remainder of
the loop in the current iteration is skipped and control passes to the condition of the loops in
while and do while loops while in a for loop, control get transferred to the increment/
decrement part. Given below is a program that prints only positive integers from 1 to 10
using a for loop and the continue statement. The program would of course be much simpler
without the use of continue statement but the purpose of this program is to help you learn
the working of the continue statement rather than code a program to print even numbers.
for (int i = 1; i <= 10; i++) {
if (i % 2 != 0) {
continue;
}
System.out.println(i);
}
Just like the labelled break statement, we also have the labelled continue statement and
this functions in a similar way. Control gets transferred to the corresponding condition (in
case of while and do while) or the increment/ decrement operation (in case of a for loop)
that that belongs to the stated label.
Just like the table above for the break statement, we present below a table for the continue
statement.
Note that the first three sets have the same output. This is because in each of the cases,
whether or not the continue statement is used, the flow of control is the same.
The last among Java's branching statements is the return statement. As we already know,
the return statement is used in methods to optionally return a value and transfer control
367
back to the calling method. To make it more simple and clear, the return statement skips the
remaining of the method. Look at the following code for example:
public class ReturnExample {
public static void main(String[] args) {
meth(true);
System.out.println("end of main");
}
public static void meth(boolean b) {
System.out.println("line1");
if (b) {
return;
}
System.out.println("line2");
System.out.println("line3");
}
}
The output of this program would be:
line1
end of main
When meth() is invoked with a true argument, the return statement is executed. This
statement causes the remaining statements in the method to be skipped and control
transfers back to the calling method. The return statement works in a similar manner when
used with methods except that a value to be returned should also be specified.
As we have already learnt, unreachable code in Java generates compilation errors. For
example any code written after the return statement in a method containing a single return
statement is an unreachable statement. We have already seen this when dealing with get
and set methods. And at that time, you have been promised that you will be shown an
example where such a usage is allowed when decision making statements are used. The
above program is such an example. The statements that print line2 and line3 are not
classified as unreachable even though they will never be executed in this particular
program. This is because they may be executed when meth() is called with a false
argument in another program. Hence, the statements are not unreachable.
This is all that we have about control structures in Java. We will now move to arrays in
which the for loop is widely employed.
368
Arrays
We have seen that variables are used to store data in a Java program. Each variable can
store not more than one data item. What do we do if we wish to store a large number of
data items, say 100. A quick answer from you might be to use 100 variables, one for each
of the 100 data items. But coding wouldn't be as simple as the answer you have given. We
need to write 100 lines of code for setting up these variables and manipulating them would
be quite a difficult task. And if we do not know beforehand, the number of variables that are
required, there seems to be solution from what we have studied till now. The answer to
such a problem lies in arrays. Arrays are the simplest data structure inbuilt into the Java
programming language. Data structures are used to store data in a more efficient way. Data
here refers to a group of data items and not a single data item for the purpose of which
variables are used.
An array is used to store a group of values, all of which have the same data type. All the
elements stored in the arrays are accessed by simply using the variable name and the
index of the element. You can think of an array as a block of cells, each having an index
starting from 0, just as we had seen with Strings. Before we move further into arrays, be
clear of the fact that an array is a reference data type just like a class. They are passed by
reference. They may be considered as reference variables and they have a name which
follows the rules of identifiers.
Here is a graphic representation of an array that contains seven elements, all having the
same data type, int. The length of the array is the number of elements contained in the
array. The length of this particular array, named by us as myArray is 7. The elements have
indices starting from 0 and extending up to 6, which is one subtracted from the length of the
array. (7-1=6). The element at index 0 is 3, the element at index 1 is 34 and so on. We refer
to the elements of the array programmatically as arrayName [ index] as we will see later on.
For instance myArray[0] contains the integer 3.
The data type of an array name is specified as <data type>[] where < data type > refers to
the data type of the elements the array would be storing. The square brackets indicate an
array. The following statements show the declaration of an array named a, which holds int
values.
int [] a;
369
The square brackets may also be placed at the end of the array name, as shown below. It
would make no difference.
int a[];
Just like variables, we may also declare more than one array in a single statement, as
shown below:
int[] a, b, c;
The above statement declares three arrays, a, b and c all of int type. However, be cautious
when using such a notation. In such multiple declaration statements, the square brackets
are placed along with the data type. If we wish to declare a few integer variables and a few
integer arrays in a single statement, we use the following form:
int a[], b, c[];
The above statement declares two integer arrays, a and c and a single integer variable b.
We however recommend that you declare not more than a single array in a statement. Now
that we have declared the array, we need to create an integer array and assign its reference
to the array variable. Just like classes, arrays are created using the new keyword. The new
keyword returns a reference to the array being created which is then assigned to an
appropriate variable. The size of the arrays (or the length, which is the number of elements
the array will hold) is also specified. Following statements creates an array to hold seven
integers and assigns its reference to eth arrays variable a.
a = new int[7];
The size of an array may be specified using integer constants as done above or by using
expression that contain variables. The following array creation statements are also valid.
int size = 7;
a = new int [ size ];
a = new int [ 3+4 ];
a = new int [ size / 3 + 5 ];
As we can specify the size of an array using a variable, arrays can be dynamically created
at run time. In other words, the size of the array can be taken as an input from the user and
an array can be created using the user entered value.
As with variables, the declaration and initialisation of arrays can be combined into s ingle
statement as shown below:
int[] a = new int[7];
370
After an array is created, all the elements are set to their default values. The above array a
has all the seven elements set to 0 implicitly.
Next, we need to access each element of the array and assign it with new int values. Array
elements are accessed by specifying the array variable and the index of the elements. a[0]
refers to the first element of the array. The following statements initialise some of the
elements of the array a.
a[0]=3;
a[1]=34;
a[5]=7;
Elements accessed with the above notation ( a[index] ) may be used just like normal
variables. We may print those values, use them in calculations, pass them as arguments
and so on.
System.out.println( a[1] );
int sum = a[6] + a[5];
double root = Math.sqrt ( a[5] );
When we specify an invalid index such as a negative number ora number hich is greater
than or equal to the length of the array, no compilation errors occur. Rather, a run time
execpetion, anmely ArrayIndexOutOfBoundsException is thrown during runtime. An
exception in Java is an object which indicates an abnormal error. We shall see how to
handle these errors in the chapter on exception handling.
There is one important thing to be noted here. While the array is a reference type, the
elements of the array are not of reference type. a[] is a reference type while a[0] is a
primitive type. For example, if we pass an element of the above array to a method and that
element is modified within the method, it shows no effect on the original value stored in eth
array. However, if the array itself is passed, it is passed by reference and is susceptible to
changes. Look at the following program which illustrates these concepts.
public class Array {
public static void main(String args[]) {
int[] a = new int[7];
a[2] = 3;
a[5] = 7;
System.out.println("Value of a[5] before passing it to the method changeElemnt() is " +
a[5]);
changeElement(a[5]);
System.out.println("Value of a[5] after passing it to the method changeElemnt() is " +
371
a[5]);
System.out.println("Value of a[0] before passing it to the method changeArray() is " +
a[0]);
changeArray(a);
System.out.println("Value of a[0] after passing it to the method changeArray() is " +
a[0]);
}
public static void changeElement(int a) {
System.out.println("In changeElement() : ");
System.out.println("Value of a before incrementing is " + a);
a++;
System.out.println("Value of a after incrementing is " + a);
}
public static void changeArray(int[] arr) {
System.out.println("In changeArray() :");
System.out.println("Value of arr[0] before incrementing is " + arr[0]);
arr[0]++;
System.out.println("Value of arr[0] after incrementing is " + arr[0]);
}
}
The output of this program would be
Value of a[5] before passing it to the method changeElemnt() is 7
In changeElement() :
Value of a before incrementing is 7
Value of a after incrementing is 8
Value of a[5] after passing it to the method changeElemnt() is 7
Value of a[0] before passing it to the method changeArray() is 0
In changeArray() :
Value of arr[0] before incrementing is 0
Value of arr[0] after incrementing is 1
Value of a[0] after passing it to the method changeArray() is 1
Note that the value of the array element a[5] in main() remain changed even after it was
passed as parameter to the method changeElemnt(). This is because a[5] is of type int (a
primitive data type) which is passed by value. a[5] is not an array type variable.
However, when the array a[] itself was passed, the value of the event a[0] was changed.
This is because a[] is of type int[] an not int. int[] is a reference type that is passed by
reference and not by value.
372
As this program has illustrated, an array type can also be taken as an argument. Also, an
array can be returned by a method. For example, a method which returns a double typed
array will have the following header:
public double[] methodName ()
We will look at an example shortly in which all these concepts are explained. There is
another way to initialise arrays by using an array initialiser. An array initialiser contains a
pair of braces which enclose the values that are to be stored in the array separated by
spaces. Following line uses an array initialise to initialise the array a[].
int[] a= { 3, 34, 7, 9};
Note that we haven't specified the length of the array in the above statement. It is
automatically calculated. When using array initialisers, separating the declaration from
initialisation isn't possible. The following set of statements result in a compilation error.
int [] a;
a = { 3, 34, 7, 9};
The length of an array can be determined through the length variable of the array object in
the following way:
int [] a= { 3, 34, 7, 9};
int len = a.length; //len = 4
Note that length is not a method of the array object but rather an instance variable.
373
examples
We may also use the enhanced for loop ( also known as the for each loop) to access the
elements of the array in a more convenient way. The for each loop has the following
syntax.
for ( <data type> <variable name>:< array name>) {
// code
}
The data type should be the same as the data type of the variables that are stored in the
specified array or it can be a higher data type. For example, when the array is of type int,
the data type specified can be long.
For each iteration of the for loop, an element of the array starting from the zeroth index is
stored in the variable specified in the header and the body of the for loop is executed. In
other words, the body of the for loop executes for each element of the array.
The following enhanced for loop is used to print the elements of the array.
int[] a ={3,4,7,9};
for ( int x: a ) {
System.out.println(x);
}
This is how the above code works. That value of x is first initialised to a[0] i.e. 3 and the
body of the for loop is executed which will causes the integer 3 to be printed on the screen.
Next a[1] i.e. 4 is assigned to x and the body executed again. In this the loop continues until
all the elements are printed.
Note that the enhanced for loop cannot replace every for loop that is used to manipulate an
array. This is because, the enhanced for loop only provides us the values held in the array
and not a means to manipulate those values unless the array contains reference type
374
variable. For example, we cannot use the for loop to initialise the array variables with the
natural number from 1 to 7, as done above using a normal for loop. This is because
elements here are of type int which is a primitive data type. Hence the variable x holds the
copy of the integer variable of the array and not a reference to the variable. Moreover, we
have no counter variables that would help in manipulating the array. However, if the array of
of a reference type, like Student, the values stored in the array cannot not just be accessed
but also modified, because in that case the variable specified in the for header (say x) holds
a reference to the Student object stored in the array.
The enhanced for loop is used to iterate through not just an array, but a collection in
general. We will see what collections are in a later chapter.
375
Execution time is determined by the numbers of statements that are excited by the
algorithm while memory requirement is determined by the additional variables that we use.
In the above program, we have used only one variable, target, which falls under memory
requirement. However, the execution time cannot be specified directly as such even if we
consider every statement to take the same time to execute. The reason is that, in this
particular algorithm, if the target is in the beginning of the array, then this search would
require only a single comparison which is known as the best case. However if the target is
located at the end of the array, the number of comparisons required would be equal to the
length of the array. This is the worst case. The average execution time would occur when
the target is located in the middle of the array. So, one thing that we can conclude is that
the efficiency of algorithms depends on the input data too. Here arises the need for a
standardised comparison of efficiencies. And one solution is the Big O notation.
The big O notation is gives us a relation between the number of data items contained in the
array and the number of comparisons required. It takes the worst case into account. It
determines how hard an algorithm has to work to obtain the result. In this particular linear
search algorithm, if the number of data items are n, then the number of compressions
required are also n. This is the order of the algorithm. Hence, linear search is said to be an
algorithm of order n.
There is a better way to arrive on this result by using the formal definition of big O. A
function f(n) is said to have an order g(n) written as O(f(n))=g(n) [ O represents order ] if and
only if, there exists an N and a c such that for every n>N, the following condition is true: 0 <
f(n) < c* g(n). What this definition has basically done is to put an upper bound on the
performance of the algorithm and take the worst case scenario.
Let us understand it in the context of linear search. We should first develop the function f(n).
Assume that each of the statements takes the same time to execute. So the execution time
is proportional to the number of statements executed which will be equal to 2*n or n or
2*n+1 depending on what you wish to regard as a statement. The important thing here is
that the power of n is 1 and not 2 or 3. This basically depends on the loop which is executed
n times (the size of the array). In the above definition, if the f(n) is substituted, you would get
g(n) as n by taking appropriate values of c and N. This might not be much clear for the
present moment. But for now, assume that order of an algorithm is the number of times the
for loop is executed for the array size, n. In this particular case, when the array contains n
elements, the for loop has to execute n times (considering the worst case scenario) and
hence the order of linear search is n.
Binary Search
Binary search is an efficient algorithm which can be used to search in a sorted array. Note
that the array has to be sorted in either ascending or descending order for the algorithm to
376
worth. Initially, the range of the array to be searched begins at the first element of the array
and extends up to the last element. This range reduces by half in every iteration. We locate
the middle element of the array and compare it with the target. If the target equals the
middle element, our search is completed, otherwise the range has to be adjusted
accordingly. For now, assume that the array is sorted in ascending order. If the middle
element is smaller than the target, then the target cannot be found in the left half of the
array as each of those elements would also be smaller than the target. Hence, we can
narrow down our search to the right half of the array. On the other hand, if the middle
element is larger than the target, we narrow our search to the left auld of the array. Clearly,
the range of elements to be searched has been reduced by half. We now perform the same
operation of finding the middle element of the new range and reduce the range accordingly.
In the second iteration, the range of elements to be searched reduces to one fourth of the
original array length. Similarly, with the third iteration, the range of elements reduce to one
eighth. Given below is diagrammatic representation of this algorithm
We now have to represent this algorithm programmatically. For this purpose, we take two
variables left and right which represent the bounds of the array to be searched. Left
indicates the left bound of the range and right indicates the right bound of the range.
Initially, the left bound is set to 0 and the right bound is set to array length -1. We then use a
while loop to perform the repetitive task of finding the middle element and comparing it with
the target event. We shall look into the termination condition of while shortly. For now, the
various things to be included in the while loop are statements to find the middle element,
compare it with the target and set the left and right bounds accordingly. Now coming to the
condition in the while loop, this process of finding the middle element and comparing it with
the target would end when we are left with just a single element. This happens when the
value of left and right becomes identical. On moving further, either right would become less
than left or left would become more than right. At this point of time, the search needs to be
stopped. Hence the loop condition is left<=right. Given below is at the code sniper for the
binary search algorithm for an array sorted in ascending order.
int[] a = {3, 7, 10, 15, 91, 110, 150}; // a sorted array not containing duplicates
int target = 91; // the element to be searched
int left = 0;
int middle;
int right = a.length - 1;
while (left <= right) {
middle = (left + right) / 2;
if (a[middle] == target) {
System.out.println("Element found at index " + middle);
break;
} else if (a[middle] < target) {
left = middle + 1;
377
378
Bubble Sort
The last of the algorithms that we are gaining to deal with is the bubble sort method. This
algorithm has its name derived from the water bubbles which surface to the top. In a similar
379
way, in this algorithm, we make larger numbers move to the top of the array when we wish
to sort in ascending order. We iterate through the array from the left to the right and
compare each pair of successive values in turn. If they are in the right order, we leave them
as they are. However, if a larger item is on the left of a smaller item, we swap them. Note
that only successive values are compared. In this way, when we move to the rightmost end
of the array, the largest value is guaranteed to have been bubbled to the top of the array.
For example, if the largest element was at index 0 initially, then in each step of comparison,
this element is moved up ultimately bringing it to the top. In this way when we repeat this
process for n-1 times, the entire array is guaranteed to be sorted. We can further improve
this algorithm by setting proper loop termination conditions. This algorithm requires two
nested loops. Within the inner loop, the loop condition can be stated to be a relation with the
outer counter variable rather than the end of the array. For example, if it is the fifth iteration,
then the four largest elements have already been bubbled to the top of the array. So, there
is no need of comparing those values gain. So, the loop condition can be specified as
j<x.length-1-i. Given below is the code for bubble sort.
int[] a = {4, 85, 7, 1, 0, 36, -5, 48};
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - I; j++) {
if (a[j + 1] < a[j]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
The bubble sort algorithm also has an order of n2. There are many more searching ND
sorting algorithms but are complicated. If you wish to learn about them, then refer to these
pages on another site:
Array of Objects
As we have already said, arrays are capable of storing objects also. For example, we can
create an array of Strings which is a reference type variable. However, using a String as a
reference type to illustrate the concept of array of objects isn't too appropriate due to the
immutability of String objects. Therefore, for this purpose, we will use a class Student
containing a single instance variable marks. Following is the definition of this class.
class Student {
int marks;
}
380
An array of objects is created just like an array of primitive type data items in the following
way.
Student[] studentArray = new Student[7];
The above statement creates the array which can hold references to seven Student objects.
It doesn't create the Student objects themselves. They have to be created separately using
the constructor of the Student class. The studentArray contains seven memory spaces in
which the address of seven Student objects may be stored. If we try to access the Student
objects even before creating them, run time errors would occur. For instance, the following
statement throws a NullPointerException during runtime which indicates that
studentArray[0] isn't yet pointing to a Student object.
studentArray[0].marks = 100;
The Student objects have to be instantiated using the constructor of the Student class and
their references should be assigned to the array elements in the following way.
studentArray[0] = new Student();
In this way, we create the other Student objects also. If each of the Student objects have to
be created using a different constructor, we use a statement similar to the above several
times. However, in this particular case, we may use a for loop since all Student objects are
created with the same default constructor.
for ( int i=0; i<studentArray.length; i++) {
studentArray[i]=new Student();
}
The above for loop creates seven Student objects and assigns their reference to the array
elements. Now, a statement like the following would be valid.
studentArray[0].marks=100;
Enhanced for loops find a better application here as we not only get the Student object but
also we are capable of modifying it. This is because of the fact that Student is a reference
type. Therefore the variable in the header of the enhanced for loop would be storing a
reference to the Student object and not a copy of the Student object which was the case
when primitive type variables like int were used as array elements.
for ( Student x : studentArray ) {
x.marks = s.nextInt(); // s is a Scanner object
}
381
Recall that we were not able to assign to the array elements in a similar way when the array
was of type int.
Moreover, in the case of array of objects, when we pass an array element to a method, the
object is susceptible to changes. This is because the element being passed is also a
reference type item. This differs from the situation when we have an int array. Following
illustrates this concept.
public static void main(String[] args) {
Student[] studentArray = new Student[7];
studentArray[0] = new Student();
studentArray[0].marks = 99;
System.out.println(studentArray[0].marks); // prints 99
modify(studentArray[0]);
System.out.println(studentArray[0].marks); // prints 100 and not 99
// code
}
public static void modify(Student s) {
s.marks = 100;
}
Compare the output with the one when the array was of type int[].
Processing an array of objects is much similar to the processing of an array of primitive
type. the only thing to be kept in mind is the possibility of NullPointerException being thrown
during run time and also remembering that the array elements themselves are reference
types, which brings subtle differences from the case when they are passed as parameters.
Moreover, an enhanced for loop may be used to initialise the array elements.
382
383
We manipulate multi-dimensional arrays using nested loops. For example, the following
code snippet is used to print the elements of an array as a matrix. The code works even
when the rows of the array are of different lengths.
for ( int i=0; i<a.length; i++) {
for(int j=0; j< a[i].length; j++)
System.out.print ( a[i][j] );
System.out.println();
}
Searching a two dimensional array is performed using a linear search. The labelled break
statement is used to break out of the loop once the element is found.
outer:
for ( int i=0; i<a.length; i++) {
for(int j=0; j< a[i].length; j++) {
if ( a[i][j] == target) {
System.out.println("Element found at ["+i+"]["+j+"]");
break outer;
}
}
}
Sorting isn't generally performed on multidimensional arrays since we generally use them to
represent a physical situation rather than as data structures to hold information. For
example, we may use a three dimensional array to hold Student objects in a more realistic
way. We have different cities and each city has different schools which has students. Let
each city, school and Student have a code. A Student object in that case can be accessed
more conveniently as s[city code][school code][student code]. This 3D representation gives
a more realistic picture than a 1D array of Students.
384
When we wish to pass the String array, we simply include the elements of the array as
simple Strings beside the class name. Enclosing the Strings in quotes is optional.
Consecutive Strings are separated with a space. For example, if we wish to pass a three
element String array containing the values "1", "2", and "3" any of the following lines is
entered on the command prompt.
java Add 1 2 3
java Add "1" "2" "3"
Since these arguments are passed through the command line, they are known as command
line arguments. The String arguments passed are stored in the array specified in the main()
declaration. args[] is now a three element String array. These elements are accessed in the
same way as the elements of a normal array. The following is the complete Add program
which is capable of adding any number of integers passed as command line arguments.
public class Add {
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i < args.length; i++) {
sum = sum + Integer.parseInt(args[i]);
}
System.out.println("The sum of the arguments passed is " + sum);
}
}
And here are some sample executions from the command line:
385
parameters. Following lines show a few valid and invalid method declarations that use
variable length argument lists.
public void meth ( int... a) // valid
public void meth (double a, int... b) // valid
public void meth ( int... a, int b) // invalid- Ellipsis may be used towards the end only
public void meth ( int... a, double... b) // invalid - More than one variable length parameter
list may not be used
public void meth ( Student... a) // valid - Reference types are also allowed
public void meth( int[]... a) // valid - reference types are also allowed
The arguments received are stored in an array of the same data type as specified in the
method header having a length equal to the number of arguments passed. Therefore, those
elements can be accessed as we access an array passed to an array type parameter. Here
is an example of a class Add containing a method addVariable() which takes variable
number of arguments, add them and displays the result. This method is invoked through the
main method with 0, 1 and 2 arguments.
public class Add {
public static void main(String[] args) {
addVariable();
addVariable(1);
addVariable(3, 4);
}
public static void addVariable(int... a) {
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum = sum + a[i];
}
System.out.println(a.length + " arguments received whose sum is " + sum);
}
}
Here is the output of this program.
0 arguments received whose sum is 0
1 arguments received whose sum is 1
2 arguments received whose sum is 7
The method taking variable arguments is called only when no exact match of arguments
occur for a given method call. For example if we had a method that accepts a single int
argument in the above class, the method call addVariable(1) would invoke this particular
386
method rather than the one taking variable number of arguments. Verify this fact yourself by
modifying the code above.
Inheritance
Inheritance is the process by which the variables and methods defined in one class become
a part of a newly defined class too. The class which inherits can define its own variables
and methods in addition to what have been inherited from the other class. As said in the
beginning, you can take the analogy of inheritance of property from parents to children. The
children inherit the property of their parents and are capable of adding their own earned
property too. Also, property inherited may be sold and given a few face in the form of a new
property. This can be implemented in Java's inheritance too. Variables and methods
inherited may be overridden to give them a new definition. We will now look into how one
class can inherit from another using the extends keyword. We will also study various other
things vital for the application of inheritance in our projects. Lastly, we shall learn about the
Object class from which all new classes inherit implicitly.
For the purpose of learning in a more natural way, we will continue with the Student
example which we have dealt with in the beginning but slightly modify it to adapt it to this
study on inheritance. We will have a class named Person which is more general in nature.
This class contains the variables name and age which every person possesses. We also
have a method printDetails() which prints the name and age. And then we develop a class
Student that inherits from the Person class. A student will have a few additional variables
like marks and rank. There will also be appropriate methods for the Student class.
Inheritance is used either to provide additional functionality to a class in the form of new
methods or to define a specific class from a general class. In this particular example, a
Person is general in nature,, while Student is more specific. Of course, specific and general
are relative and depend on the objects that are taken into consideration.
The class from which a new class inherits is known as the super class. It is also called by
other names such as base class, main class and parent class. The class which inherits from
the super class is known as the subclass, also referred to as derived class, extended class
and child class. But, we generally use the terms super class and sub class. In this particular
example, Person is the super class and Student is the Sub class. Let us first define the
Person class in the following way with two variables, a constructor and a method.
public class Person {
String name;
int age;
387
388
}
}
The class Student declared above has not just marks, but also a name and an age. To
verify this, provide some method m() and try to access these variables and the method
printDetails() in the following way. Compile the program and you will not receive any
compilation errors. This confirms that variables and methods of the super class have been
inherited by the sub class.
public void m() {
name=null;
age=-1;
printDetails();
}
However, if we try to access private variables of the super class from the sub class,
compilation errors occur. This is because the scope of private instance variables is limited
to the class itself. In order to modify such variables from the super class, we need to provide
set and get methods or other similar methods in the super class which can then be called
from the sub class. In the above program, change name to private, and provide getName()
and setName() method in the Person class. Call these methods from the method m() in the
following way and compile.
String str=getName();
setName("No name");
Variables and methods inherited from the super class retain their access specifiers. A public
variable is still public and a variable whose access specifier is unmentioned is still treated in
the same way in the sub class also. For example, we can write a Test program for the
Student class, create its objects and access the variables name and age through the object
as they are still public.
Student s = new Student ("Sai", 19, 99);
s.age=18; // valid
If we declare variables in the sub class which have the same name as the variables
declared in the super class, then these variables would hide the ones declared in the super
class. This is similar to how local variables hide instance variables. For example, define a
new variable age in the Student class.
int age;
This age variable hides the age variable that has been declared in the super class. Now, the
Student class has two age variables, one of which has been defined in the Person class
389
and the other defined in the Student class itself. When we refer to the variable age in a
method of the sub class, we get access to the sub class version of age and not the super
class version. The sub class version has hidden the super class version. To get access to
the super class variable, we use the super keyword in the following way:
super.age= 10; // gives access to the super class' version
In a similar way, we can also hide the methods of the super class. This is more aptly
referred to as method overriding. A method in the super class is said to override the method
in the sub class when it has the same method signature which includes method name and
the number, order and type of parameters. The names of parameters are irrelevant. We can
override the method printDetails() in the Student class so that the marks of the Student are
printed in addition to the name and age of the Student. Note that we can also call the super
class version of printDetails() in order to display the first two items.
public void printDetails(){
super.printDetails();
System.out.println("Marks: "+marks);
}
If a method in the sub class has the same name and parameter list as another method
defined in the super class, then it needs to have the same return type also. Otherwise
compilation errors occur. Moreover, stricter access specifications may not be applied to the
overridden methods. This is known as attempting to assign weaker access privileges. The
weakest of access privileges is private followed by unspecified, protected and public. A
method that was public may not be overridden with a method that is private. However, a
private method may be overridden with a public method. Also, to make sure that we are
writing an overridden version of an already method and not a new method, we may use the
'@ Override ' annotation. This is specified prior to method declaration in eth following way.
@Override
public void printDetails(){
//code
}
It is always recommended to use this annotation whenever methods are being overridden.
When this annotation is used, the compiler checks that this method's signature matches
with the ones existing in the super class. If no match is found, a compilation occur occurs.
This is important to ensure that our code is not affected by typographical errors. For
example, if in the Student class, we incorrectly type the method name as printDetails()
instead of printDetails(), the method will be considered to be a new method. When Objects
of Student are created and the printDetails() method is invoked on them, the method
390
defined in super class called. In order to avoid such trivial errors, the use of @Override
annotation is recommended.
The principle of least privileges is not applicable to variables. We may have a public
variable in the super class and a private variable in the subclass both with the same which
isn't possible with methods. When the objects of sub class are created and the access to
this variable is given based on the specifiers associated with the variable defined in the
subclass, which in this case is private leading to denial of access. Moreover, such variables
are also not accessible in classes derived from theses sub classes.
Subclasses may be further extended to another class. This is known as multi-level
inheritance. For example, we can extend the Student class above to a new sub class
StudentWithDisabilities. Now, this new class will have the variables and methods of both of
its super classes. A class is called as either a super class or a sub class depending on the
context in which it is being seen. For example, the Student class is a sub class with respect
to the class Student while it is a super class with respect to the class
StudentWithDisabilities. We will look into multi-level inheritance later on. The inheritance
which we have seen till now is single inheritance where a class extends a single super
class. Java does not support multiple inheritance (not to be confused with multi-level
inheritance) Multiple inheritance is the form of inheritance where a class can extend more
than one super class. We will look into multiple inheritance later on. For now, here is the
complete Student sub class with the overridden method and a Test class. we have also
provided an extra method showGrade() which displays the grade of the Student.
public class Student extends Person {
int marks;
public Student(String n, int a, int m) {
super(n, a);
marks = m;
}
@Override
public void printDetails() {
super.printDetails();
System.out.println("Marks: " + marks);
}
public void showGrade() {
char grade;
if (marks >= 90) {
grade = 'A';
391
392
object to a super class variable type. However, the reverse is not true. A reference of a
super class object may not be assigned to a sub class variable. The following statements
illustrate this concept by creating a Student object and assigning it to a Person variable.
However, when we try to assign the reference of a Person object to a Student variable, we
get a compilation error.
Person p=new Student("Sai", 19,100);
Student s=new Person("Ram",18);//error
This 'is a' relationship finds application in other areas too. For example, we can pass a
Student object to a method which requires a Person object and we can return a Student
object from a method whose return type is Person.
public Person someMethod () {
Student s=new Student ("Sai", 19,100);
return s; // allowed
}
public void needAPerson ( Person p ) {
// code
}
public void aMethod() {
needAPerson ( new Student("Sai", 19,100) ) ; // allowed
}
The methods and variables of a class that are accessible will depend on the variable type
and not the object type. For example, if we try to access the marks variables or the
displayGrade() method of the Student object p above, we receive compilation errors. This is
because, the accessible methods and variables are determined by the type of the variable
and not the type of the object.
p.marks=100; // error
p.showGrades(); //errors
The reason behind this is that the sub class isn't aware of any of the super classes that
have been derived from it. Hence, it cannot assure that the object contains a marks variable
or the showGrades() method.
This may sound unusual but you will agree that this is the correct way if you look at the
following method and read the discussion that follow it.
393
394
variable through a super class variable holding a reference to a sub class object, we get the
value corresponding to the super class variable and not the sub class variable, contrary to
what was observed in the case of methods. The following example makes this concept
clear.
class A {
int var = 10;
}
class B {
int var = 20;
}
// in the main method of a class, write the following code
A obj =new B();
System.out.println(obj.var); // prints 10 and not 20
In order to check whether an object is of a particular class type, Java provides the
instanceof operator (or keyword). This operator requires two operands, the first is a variable
name and the second is a class type. The operator returns either true or false.
Student s=new Student("Sai", 12, 100);
boolean result1 = s instanceof Student; // true
Person p = new Person ("Ram", 18);
boolean result2 = p instanceof Person; // true
The 'is a' relationship shows its effect on the working of instanceof operator also. A sub
class object is an instance of it super class. Hence, the following behaviour.
boolean result3 = s instanceof Person; // true
The instanceof operator may be used to check whether a particular object passed is of the
required data type. For example, if a method needs a Person object, a caller may pass a
Student object also. To process these two types separately, we may use a code similar to
the following:
public void process ( Person p ) {
if ( p instanceof Student ) {
// code
} else {
// code
}
}
395
We will come back to the instanceof operator once again when we deal with interfaces. The
next topic to be dealt is casting from one class type to another. Just as we cast primitive
data items, we can also cast reference data items to a different class type. Here too, the
concepts of up casting, down casting, explicit casting and implicit casting come into picture.
Implicit casting is performed in situations where we assign the reference of a sub class
object to a super class variable, pass a sub class object reference to a method where a
super class object is required or return a sub class object when a super class return is
specified. In all these cases since a lower data type is converted to a higher data type, it is
an up casting operation or type widening operation. Super classes are higher data types
and sub classes are lower data types.
Person p = new Student ("Sai", 19,100); // implicit casting
Student st = new Student ("Sai", 19,97);
Person pe = st; // implicit casting
We may also perform explicit casting, using the cast operator as shown below.
Student s= (Student) p;
The above statement does not create a new Student object identical to p. It simply casts
into to a Student type. Now, p and s refer to the same object and hence, changes made to
the object through any one of the objects are reflected on the other.
Person p = new Student ("Sai", 19,100); // implicit casting
Student s= (Student) p;
s.age=20;
System.out.println(p.age); // prints 20 and not19
When we cast objects from one type to another, the compatibility of these types is checked.
For example, a Student object cannot be cast to String type as they are incompatible.
String str= (String) s; // error, s is a Student object
Just like the 'is a 'relationship, we also have the 'has a' relationship which is quite
straightforward. A class A is said to have a 'has a ' relationship with a class B if class A
contains an instance variable of type B.
class A {
B obj;
}
class B {
}
396
397
classes named Car and Vehicle defined in the following way and of course with may other
methods of your own.
public class Car {
public void move() {
System.out.println("Moving on road");
}
}
class MoveAVehicle {
public static void move(Car c) {
c.move();
}
}
Now, since the class Car is not final, other people may extend it to their own classes.
Following is an example:
class Aeroplane extends Car {
public void move() {
System.out.println("Moving in air");
}
}
This is logically wrong. An aeroplane is definitely not a Car. And a statement like the
following would print absurd data on the screen.
MoveAVehicle( new Aeroplane() );
In order to avoid such illogical extending of classes; classes and methods may be marked
as final. The example cited above is just illustrative. The actual scenario in real world
programming is much more complex.
398
package and include a class in a particular package. A package isn't created by any explicit
statement. It is automatically created when a class is specified to be a part of that package.
A class is declared to be a part of a particular package by including the package statement
at the top of the class. The package statement should be the first statement in a program
file, even before import declarations. However comments are allowed to be placed before
the package statement. The following program defines a class A and places it in the
package named mypackage1. Package names are by convention written in all lowercase
letters even if they consist of multiple words.
package mypackage1;
class A {
protected int num;
}
And, the following defines a new class B in package mypackage2. This class consists of a
variable of type A. When one tries to access the variable num of class A, compilation errors
occur. This is because, num has protected access. It is accessible only within the same
package and within its subclasses.
package mypackage2;
class B {
A objA;
public B() {
objA = new A();
objA.num = 34; // not allowed
}
}
The above access is permitted if B is defined to be a subclass of A or if it in defined in the
same package as that to which A belongs, even if it is not declared to be a subclass.
package mypackage2;
class B extends A {
A objA;
public B() {
objA = new A();
objA.num = 34; // not allowed
399
}
}
When a class is not specified to be a part of any package, it is placed in the default
package. This default package and the java.lang package are imported into all classes
implicitly. A package can in turn contain other packages. For example, we can have another
package p2 in the package mypackage in eth following way.
package mypackage.p2;
class B {
}
Now, with respect to access restrictions, the class A and B are considered to be in different
packages. Protected variables of class B are not accessible from class A. Similarly,
protected variables of class A are not accessible from B.
Class Object
The Object class lies at the root of every hierarchy. In other words, every class is a direct or
an indirect superclass of the Object class. If we do not specify a superclass using the
extends keyword, the default is the Object class, otherwise the Object class becomes an
indirect superclass due to multilevel inheritance.
class A {
}
A extends Object implicitly.
The Object class has certain useful methods, notable among them being the equals()
methods. Since, every class is either a direct or an indirect superclass of the Object class,
these methods can be invoked on any object and a reference of any object can be assigned
to an Object type variable, including an array type.
Object obj = new int[5];
Object s = new Student ("Sai", 19, 97);
We can also create an object of the Object type using the constructor. However, such an
object finds no useful application.
Object obj= new Object();
The Object class defines 11 methods, five of these are used in the context of multithreading
which we will see when we deal with multithreading. We shall now look at some of the
remaining methods.
400
401
call gets resolved to the other version inherited from Object which checks for references
and would surely return false. Given below is the overloaded version:
public boolean equals(Student s) {
if (this.name.equals(s.name) && this.age == s.age && this.marks == s.marks) {
return true;
} else {
return false;
}
}
This overloaded version checks if the name, age and marks of both the Student objects are
identical and returns true or false accordingly. Note the use of this in the above method to
refer to the Student object on which the equals() method is invoked with a Student
argument.
We may if we wish to also override the method. The implementation would then vary
slightly. First, we need to check if the object passed is of Student type. If it isn't, then there
is no chance for it to be equal to the object on which the method is invoked. Hence, we
return false. Otherwise, the object passed is explicitly down casted to Student type and we
perform a comparison as done in the overloaded version above. The @ Override annotation
below is optional but recommended.
@ Override
public boolean equals(Object obj) {
if (!(obj instanceof Student)) {
return false;
} else {
Student s = (Student) obj;
if (this.name.equals(s.name) && this.age == s.age && this.marks == s.marks) {
return true;
} else {
return false;
}
}
}
Note that we have use the equals() method rather than == to compares the two names
which are Strings. After theses modification, the result of the equals() method call, which we
have seen would now change. res1 becomes true.
402
The toString() method returns a String representation of the object on which it is invoked.
This String contains the class name followed by the @ sign and the hexadecimal
representation of the object. Do not bother about what hash code is.
Student s = new Student ( "Sai", 19, 100 );
String s=s.toString(); // s1=" Student@addbf1"
When we pass an object as a parameter to the print() or println() statement, the toString()
method is implicitly called on the object and the String is printed on the screen.
System.out.println(s);// prints " Student@addbf1"on the screen
The toString() method can be overridden to return a better representation of the object. For
example, in the case of Student class, we can return the name, age and marks of the marks
along with the class name, in the following way.
@ Override
public String toString() {
String s="Student: "+this.name+" "+this.age+" "+this.marks;
return s;
}
Now, we may either explicitly call this method or implicitly call it by passing a Student object
as a parameter as in the following code.
Student s = new Student ( "Sai", 19, 100 );
System.out.println(s);// prints "Student: Sai 19 100"
If we wish to do so, we may copy the definition of printDetails() method into the overriding
toString() method and remove the printDetails() method. Since, the printDeatils() method's
task is to essentially convert the object to a String.
403
Instead of using the statement s=null to remove the reference to the object created on the
first line, you may also use the following statement which creates a new object and assigns
its reference to s. So, the object referred to earlier has no references now.
s= new Student("Sai", 18,100);
There is no way we can retrieve the object created earlier. If too many such abandoned
objects exist, they occupy significantly memory and waste the resources available. The
automatic garbage collector of Java destroys such objects. But before doing so, three may
be a need for that object to return back any resources that it has used. For example, if it had
opened a file, ( we ill see later how it is done), the object needs to first close that files before
destroying itself so that other objects can open that file. All such operations may be
specified by overriding the finalize() method. The finalize() method defined in the class
Object has an empty body. Shown below is an overridden version of this method for our
Student class. This method simply states that the object is being destroyed.
@ Override
protected void finalize() throws Throwable {
System.out.println("Object being destroyed");
}
We shall see what 'throws Throwable' means when we deal with exception handling but for
now, it indicates that the method might throw Exceptions. The method finalize() should
never be called explicitly. It is automatically called by the garbage collector when needed
but one cannot be assured of when it will be called and if it is guaranteed to be called. We
shall see after dealing with multithreading how we can realise the execution of the finalize()
method. And, if we call the finalize() method, it doesn't destroy the object on which it is
called. It only executes the body of the finalize method. We do have other methods: clone(),
hash code() and get Class() and the multithreading related functions. In you are interested
in learning about them, visit this page.
Polymorphism
Polymorphism is an object oriented programming feature which allows the same message
to produce different but correct outputs. One example is the case of method overloading,
the same message sent ( invoking the method) produces the desired and correct output by
resolving the call to the appropriate method based on the parameters passed. And now, we
shall see polymorphism in the context of inheritance. Polymorphism allows us to program in
the general rather than in the specific. We have already come across polymorphism in the
context of inheritance when we have overridden the printDetails() method in the Student
class. Invoking it has called the sub class version and not the super class version. We shall
404
continue a similar discussion, using a different and more appropriate example to illustrate
programming in the general.
We have a class named Animal having a method move(). An animal may move in different
ways, it might swim like a fish, fly like a bird or crawl like a spider. So the class Animal is
more general, so is the method move(). We then extend this superclass Animal to a few
subclasses like Fish, Spider and Bird which override the method move() to define a more
specific implementation of the method move(). For now, here are the various class
definitions.
public class Animal {
public void move() {
System.out.println("The animal is moving");
}
}
public class Bird extends Animal{
public void move() {
System.out.println("The bird is flying");
}
}
public class Fish extends Animal{
public void move() {
System.out.println("The fish is swimming");
}
}
public class Spider extends Animal{
public void move() {
System.out.println("The spider is crawling");
}
}
public class Hare extends Animal{
public void move() {
System.out.println("The hare is running");
}
}
Animal is a more general class and the sub classes are more specific in nature. There is
also a possibility that we may feel like adding more Animal types or subclasses of Animal in
the future. So, rather than programming with respect to a specific animal, we simply
405
program in the general taking only the Animal class into consideration and not its specific
sub classes.
To understand what programming in the specific and general means, let us assume that we
need to create ten different objects, some of them of Bird type, a few others of Spider type
and so on. And then make each of these animals move. One solution would be the following
where we consider each animal to be of a separate type. This might be named as
programming in the specific.
Fish f1 = new Fish();
Fish f2 = new Fish();
Bird b1=new Bird();
...
f1.moev();
f2.move();
f3.move();
...
This approach seems alright but what if we have 100 such different animals, a few in each
category? And if is not just one method that we need to invoke but several of them, all of
them having the same name and defined in each of the classes. One solution would be to
use arrays. Now, here arises the question. Do we create Fish arrays, Bird arrays or Animal
arrays. If we go for creating a different typed array for each of the Animal types, modifying
the code would be difficult if new Animal types like Crabs and Monkeys come into the
picture. So, we better choose to create arrays of Animal type. But, would move() invoked on
Animal type objects call the version in the superclass or the sub class? As we have already
seen when earlier, during compilation, the method call is resolved by looking at the variable
type which in this case is Animal. So each of the move() calls would be mapped to the
versions in superclass. However, the actual method being called is decided during time by
looking at the type of object and not the type of variable. If the sub class has overridden any
of the already matched methods during compilation, the call would be diverted to the sub
class method. So, the correct version is guaranteed to be called. This is what we refer to as
programming in the general and this resolution of calls during run time is known as dynamic
binding or run time polymorphism. Actual use of this feature is quite more complicated and
is used as a part of actual reusable class. But, for illustrative purpose, we use it in test class
as shown below:
public class Test{
public static void main(String [] args){
Animal[] animals=new Animal[4];
animals[0]=new Fish();
animals[1]=new Spider();
406
animals[2]=new Bird();
animals[3]=new Hare();
for(int i=0;i<animals.length;i++)
animals[i].move();
}
}
The output would be:
The fish is swimming
The spider is crawling
The bird is flying
The hare is running
To make this program more interesting, provide parameterised constructors for the sub
classes of Animal so that we may give names to the animal and modify the move() method
to display the name of the animal along with the action being performed.
Method call resolution during run time occurs to the deepest level. For example, if in the
above program, we further extends Bird to Sparrow overriding method move(), create a
Sparrow object, assign its reference to an Animal variable and then invoke the move()
method, the call gets resolved to the version in Sparrow and not to the one in Bird() or
Animal().
Interfaces
A Java interface is used to specify what is to be done but not how it is to be done. For
example, a Vehicle should be capable of performing several tasks such as starting,
stopping and changing speed. All types of vehicles, be it a car or an aeroplane should be
capable of doing these tasks. In such a case, we can define an interface Vehicle where
these various methods are specified but the definition of these methods are given in the
classes like Car and Aeroplane which implement these interfaces.
A Java interface consists of only final static variables and abstract methods. No
implementation is provided for the methods. We may declare the vehicle interface in the
following way:
public interface Vehicle {
// body
}
407
The interface name follows conventions similar to those followed by class names. The first
letter of each word in an interface is capitalised. The access specifier may be either public
or unspecified. When stated as public, the interface is available to all classes. When no
access specifier is stated, default access restrictions are applied and the interface is
accessible only from classes within the same package. private and protected access
specifiers cannot be used here. The interface may not be private because it should be
accessible from other classes if they are to implement. On similar lines, the use of protected
is absurd since an interface is mainly defined to be implemented in a class and there exists
no such thing like a class inheriting an interface because of which protected would offer the
same level of protection as the package specifier. Hence, its use is absurd.
The interface may contain both variables and methods. Variables are implicitly final, static
and public. And the methods are implicitly abstract and public. Use of specifiers that
overwrite these default specifiers is not allowed. For example, both methods and variables
may not be declared with the public or protected specifiers. The reason behind this is the
same as discussed above with reference to the interface.
The following example shows the interface Vehicle with three abstract methods and a final
variable code.
public interface Vehicle {
int CODE = 347; // implicitly public and final
void start(); // method is implicitly public and abstract
public void stop(); // method is implicitly abstract
public abstract void changeSpeed(int newSpeed);
}
Note that the variables declared in an interface should be initialised with default values as
final variables require that they be initialised at the time of declaration itself. A class which
implements this interface should provide the definition for all of the abstract methods. Given
below is an example.
public class Aeroplane implements Vehicle {
int speed;
public void start() {
System.out.println(" Taking off");
}
public void stop() {
System.out.println(" Taking landing");
408
}
public void changeSpeed(int s) {
speed = s;
}
}
Note that the variable names used in the parameter list of the method name in this class
and those defined in the interface need not match as was the case always. We have used
the variable name s instead of newSpeed.
The @Override annotation may be used here too to ensure that we are using the correct
method definition.
A statement like the following would be valid since the variable CODE is now a part of the
class Aeroplane too as the interface Vehicle containing the variable CODE has been
implemented.
System.out.println(CODE);
Even a class that does not implement an interface can access the variables defined in the
interface since they are static.
int code= Vehicle.CODE;
A class can implement more than a single interface. These interfaces are included in the
class declaration with a comma separated list as shown below.
public class Aeroplane implements Vehicle, AnotherInterface {
}
Moreover, a class can define its own additional variables, methods and constructors just like
any other class. Also it can extend a superclass in addition to implementing the interfaces.
An interface can also be implemented by more than a single class.
If a class does not provide the implementations of all the methods declared in the interface,
the class itself should be defined as abstract. These abstract methods can then be defined
in classes which extend it.
An interface also works as a data type. Though objects of an interface cannot be created,
we can assign to the variable a reference of an object belonging to a class which implement
the. For example, we can assign the reference of an Aeroplane object to a Vehicle variable.
Vehicle v = new Aeroplane();
409
The above statement indicates that there is an 'is a ' relationship between the class the
implementing classes and the interface and hence the following applications and results.
public Vehicle meth() {
return new Aeroplane();
}
public void someMethod( Vehicle v ) {
//code
}
// call to the above method
someMethod( new Aeroplane() );
// use of instanceof
Aeroplane a=new Aeroplane();
Boolean b=a instanceof Vehicle; //true
The above technique of considering an interface as a data type brings out the reason
behind the use of an interface. One can code a class containing calls to start() and stop() on
vehicle objects unbothered about the type of Vehicle- an Aeroplane or a Car. Since only
objects of types that have implemented the Vehicle interface can be passed to the class,
there is no need to worry if the class has the methods start() and stop(). However, to use
method other than those defined in the interface, the object needs to be cast to an
appropriate type. For example, consider that the Aeroplane class has an additional method
flyHigher(). This method called be invoked on an object through a variable of type Vehicle
only after explicitly casting it.
Vehicle v=new Aeroplane();
v.flyHigher(); // compilation error
This is because the interface Vehicle hasn't declared a flyHigher() method. To be able to
call this method, the object needs to first cast to an Aeropalne.
Aeroplane a=(Aeroplane) v;
a.flyHigher();
Interfaces can also be extended just like classes using the extends keyword. But unlike
classes, an interface can extend more than one interface by using a comma separated list.
public interface SuperVehicle extends Vehicle {
// code
}
410
The new interface will also posses all the variables and methods declared in its super
interfaces.
Inheritance is generally in the context of interfaces when extending an interface is
necessary. For example, consider that the above Vehicle() interface has been implemented
by many other developers. Now, if you add another method to this interface, all the classes
created by the other developers would break as a class when implementing an interface
should provide definitions for all the methods that have been declared in the interface. The
developers will have to modify their classes before they can be used once gain. To avoid
such complication, interfaces are extended when one wishes to modify them by adding new
methods.
Packages
We have come across packages many times. We have also used them in a few instances.
We will now review all those concepts and also look into the unexplored items. We start with
what a package is. A package in Java is used to group related classes together. For
example, we can have a package named shapes which will contain various classes like
Circle, Triangle and Square used to process various geometric shapes. Packages are also
used to resolve namespace conflicts. Two classes cannot have the same name under
normal circumstances. However, if they are declared in different packages, you can have
more than a single class with the same name.
Packages are created when the program files are compiled. You can specify a class to be a
part of a package by using the package keyword before any other code in your class,
including class declaration and import declarations. You can however have comments
before the package statement as they are ignored by the compiler. The following code
declares the class Triangle to be a part of the package shapes. A package name by
convention is written in all lowercase letters even if they consist of more than a single word.
package shapes;
class Triangle{
// code
}
A package can in turn contain other packages. You specify this using a dot. For example, if
you would like to include a class, say Cube in a package named threed which should be a
part of the package shapes, then you do it in the following way.
package shapes.threed;
class Cube {
411
//code
}
Understand that we include packages within packages only to represent the physical
situation. The two packages shapes and shapes.threed are considered to be different
packages when we deal with access protection and package imports. For instance, if the
class Cube is declared as protected, then it would not accessible to the class Triangle since
they both are situated in different packages. However, as already said packages are
defined in this way to represent physical relations which are reflected in the way the
compiled classes are organised. To understand this, define the following classes in different
program files all in a single folder on your computer and compile them.
package shapes;
class Triangle{
}
package shapes;
class Rectangle{
}
package shapes.threed.sixfaces;
class Cube {
//code
}
package shapes.threed;
class Sphere {
//code
}
package shapes.threed.sixfaces;
class Cuboid {
//code
}
package shapes.threed.fourfaces;
class Tetrahedron {
//code
}
In all we have six classes. After compiling them, observe how the Class files generated are
arranged in the folder. A new folder shapes has been created which contains Triangle.class,
Rectangle.class and another folder named threed. The threed folder contains Sphere.class
412
and two folders: sixfaces and fourfaces. The six faces folder contains two files : Cube.class
and Cuboid.class. The folder fourfaces contains a single file Tetrahedron.class.
When a class is not specified to be a part of any package, it is then placed in the default
package. In terms of a folder, the .class compiled file is placed in the same folder in which
the .java file is present.
In order to use a class of a package other than the one to which the class we are working in
belongs to, we need to import either that particular class or the entire package in which the
class is located. Or, we can refer to the class by its fully qualified name. To import a
package or a class, we use the import declaration placed after the package statement. To
import a class or the entire package, we use the following syntaxes. To import more than
one class, we specify each of these import declarations in different statements.
import <package name>.<class name>;
import <package name>.*;
The second statement above imports all the classes that are located in the specified
package. Given below are a few import declarations for the above classes we have defined.
Note that an import declaration similar to the second statement above does not import the
classes contained within sub packages of the specified package. It only imports the classes
of that package. For example, importing shapes imports only Triangle and Rectangle. It
doesn't import the other classes, Cube, Cuboid and Tetrahedron. The package shapes and
shapes.threed are considered to be different.
import shapes.Triangle; // imports Triangle
import shapes.Rectangle; // imports Rectangle
import shapes.*; // imports both Triangle and Rectangle
import shapes.threed.*; // imports Sphere
import shapes.threed.sixfaces.*; //imports Cube and Cuboid
import shapes.threed.sixfaces.Cube; // imports Cube
Specifying only the package name without the class name or the asterisk (*) results in
compilation error.
import shapes; // compilation error
Also, the * is not a general wild card character in this context. The asterisk is in daily life
used as a substitute for a sequence of characters. For example T* may represent Tea, Tree
and so on. However, here, the * is not a wildcard character and such a use isn't allowed.
For example, the following statement generates a compilation error.
import shapes.T*; //compilation error
413
Once we import a class, we can use that class by referring to its simple name. See the
example below:
import shapes.Triangle;
class Test {
Triangle t; // referring to with its simple name
public Triangle meth() { // referring to with its simple name
}
public void action(Triangle t) { // referring to with its simple name
}
}
We can also use a class without importing it. In that case, we need to refer to it using its
fully qualified name which includes the package name, followed by a dot and the class
name. For example, to create a Sphere object, we use the following statement:
shapes.threed.Sphere s = new shapes.threed.Sphere();
In a similar way, the following statements:
public void action(shapes.threed.Sphere s) { // referring to with its simple name
}
Such a use is highly inconvenient, hence it is always recommended to import the classes
before using them. However, in certain circumstances, this might not be possible when
name conflicts appear. Suppose, we have two packages p1 and p2 both containing the a
class with the same name MyClass, then importing both the classes is allowed but that
does not mean that we can refer to the either of the class with its simple name. For
example, see the following statements. The identifier MyClass cannot be resolved to either
of the two versions.
import p1.MyClass;
import p2.MyClass;
class Test {
MyClass m ; // compilation error
}
In such a case, the only available solution is to refer to the class with its fully qualified
name.
414
415
A method is declared with the abstract specifier if we wish to only declare it and not provide
its implementation. For instance, in the previous example, we could have defined the
method move() as abstract if we are sure that three does not exists any general Animal.
public abstract void move();
Note that there is a semicolon at the end of the method declaration which indicates that the
method is not yet defined. A class containing one or more abstract methods should also be
declared as abstract. Mentioning something as abstract simply means that the item under
context is not yet usable and further actions are necessary to make it usable.
abstract class Animal {
//code
}
We may also declare a class as abstract even when the class contains no abstract
methods. But when a class contains atleast a single abstract method, the class also needs
to be abstract. Otherwise, compilation errors occur. Objects of an abstract class cannot be
created. Even then, constructors may be provided for an abstract class for use by its sub
classes. An abstract class is made usable by extending it to a sub class. The sub class
needs to provide implementations of all the abstract methods defined in its super class, just
in the way methods are overridden. No special syntaxes exist for it. If one or more of the
abstract methods of the superclass are not defined in the sub class, even the sub class
needs to be defined as abstract. In addition, it may declare its own abstract methods. When
a new class extends another class, it needs to provide implementations of not just the
abstract methods of its immediate superclass but also of all the other indirect superclass's
lying in the hierarchy. Though we may not create an object of an abstract class, we are free
to declare a variable of that abstract class type. We can then assign references to objects of
the subclass type to these superclass variables.
Animal a = new Bird();
The abstract word is often used in association with the advantage provided by
polymorphism. For instance, in the example we dealt with, creating an Animal object might
seem absurd. Hence, we may declare it to be abstract with no other changes required.
During compilation, the method call move() would be resolved to the version in Animal class
itself even though it has been declared to be abstract. This is because, any object reference
that has been assigned to this variable is guaranteed to have an implantation of the move()
method failing which, an object of the Animal type (by way of inheritance) could not have
been created in the first place.
416
The keywords abstract and final may not be used together. This is because an abstract
method or a class should be extendable by other classes. Otherwise, there is no point in
defining those classes.
abstract final class A // compilation error
abstract final void meth(); // compilation error
Exception Handling
A program may not always reach to its end. It might be interrupted in several ways. A logical
error in your program could crash it. For example, you might be trying to access an element
of an array beyond its length. The misbehaved user could enter a String when asked for an
int and lastly, the computer itself could go out of memory requiring the program to end.
Some of them cannot be handled but the others can. For example, if a user enters a String
when an int is needed, the program would terminate abruptly printing an error message. We
can override this default behaviour so that the program asks for a proper input a second
time. This is attained using Java's exception handling statements.
An Exception in Java is an object which contains information about the error that has
occurred. These Exception objects are automatically created when an unexpected situation
arises. If we do not provide any exception handlers, as already told, an error message is
printed. Before we learn how to provide our own exception handlers, let us see what the
default handler provided by the compiler does. For this purpose, let us write a program
which takes an int as an input from the keyboard. Simulating a misbehaved user, let us
enter a String instead of an int. Here is the program for this purpose.
import java.util.Scanner;
public class TakeInput {
public static void main(String[] args){
Scanner s=new Scanner(System.in);
System.out.print("Enter an integer: ");
int num=s.nextInt();
System.out.println("You entered "+num);
}
}
And here is a sample output when we enter the String "Java" when we were supposed to
enter an integer.
Enter an integer: Java
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:840)
417
at java.util.Scanner.next(Scanner.java:1461)
at java.util.Scanner.nextInt(Scanner.java:2091)
at java.util.Scanner.nextInt(Scanner.java:2050)
at TakeInput.main(TakeInput.java:7)
As you can see in the output above, the program was terminated midway. The last
statement which prints "You entered ..." was not executed. The method nextInt() expects an
int but what it received is a String. And so, the method nextInt() has thrown an
InputMismatchException which you can see on the second line of the output. This
Exception has occurred in the main thread. We shall see in a later chapter what a thread is.
And the remaining lines point out to the code where this particular Exception has occurred.
This is known as unwinding the stack trace.
To know what a stack trace is, let us consider the following program.
class Example {
public static void main(String[] args) {
a();
}
public void a() {
b();
}
public void b() {
c();
}
public void c() {
}
}
The execution of this program starts with the main() method. From main(), the method a() is
invoked. a() then invokes b() and finally b() invokes c(). After c() completes its execution,
there should be a way to know as to where which the control should be tranferred, b(), a(),
main() or a method in some other class? This information is held in method activation stack.
A stack is a data structure (data structures store information) onto which items can be
pushed or popped (removed). You can think of a stack as a pile of books. We place books
on an existing stack of books only on the top and we also remove books only from the top.
We don't insert or remove books from the middle of the pile. A stack is therefore, a first in,
last out data structure since the data item which is pushed onto the stack first is popped out
of the stack at the end. A record of method calls is held in such a stack. When a method is
418
pushed onto a stack, the line number of the other method to where it should return and the
argument variables of the current method are also pushed onto it. This is why the scope of
the argument variables end when the method completes execution as these variables are
pushed out of the stack along with the method record. So, in this program, the method
main() is first pushed onto the stack followed by a(), b() and c(). If c() invokes a method of
some other class, even that would be pushed onto the stack. Once c() completes execution,
it is popped out of the stack and control passes to the method b(). Next b() is popped out in
a similar way followed by a(). In this way, the virtual machine executing the program is
capable of knowing where to return back.
Now, we move back to the sample output of the TakeInput class. Look at the lines in the
output. The method stack has been unwound. The line numbers on which the error
occurred are also printed. We haven't explicitly invoked any method by name forNext() or
next(). These were invoked from within the nextInt() method which we have called. Hence,
they too are printed in the stack trace. The line numbers are also displayed which would
help us in finding the source of error.
However, a user using this program might get confused on seeing such lines of code. An
alternative way to program would be to display a message that he has entered an invalid
value and stop the program rather than allowing the above messages to be printed. We do
it by using try catch finally blocks. A try block encloses the code which may throw
Exceptions. You can find out if a particular method throws an Exception by looking at the
documentation of the class. Along with the method names and descriptions, the exceptions
that it may throw are also listed. The catch blocks provide a means to handle these
Exceptions. A try block may be followed by any number of catch blocks. Each catch blocks
handles a particular type of Exception. As we have already said, an Exception is an object.
The corresponding catch block receives the Exception thrown by the try block into a
variable specified in eth catch clause and processes the Exception. And lastly comes the
finally block which contains code that will be executed whether or not an Exception has
occurred.
try {
// code
} catch ( <Exception type > < identifier > ) {
// code
} // more catch blocks
finally {
}
If no Exceptions are thrown by the try block, none of the catch blocks are executed. Control
passes directly to the finally block. However, if an Exception is thrown by the try block, then
the remainder of the code in try block is skipped and the type (class type) of the Exception
419
is compared with each of the catch blocks in the same order in which they are defined until
a match if found. When an appropriate match is found, the corresponding catch block is
executed and the remaining catch blocks are skipped. And then the finally block is
executed. A try block should be followed by atleast one catch or finally block. One important
thing that should be remembered is that variables defined in any of the try, catch of finally
blocks have their scope and lifetime limited to that block itself.
The following program shows a modified version of the TakeInput program where the
statements are enclosed within the try block. The Exception that might be thrown here is a
InputMismatchException and hence a catch block has been provided to handle it. Look at
the code within the parentheses following the catch keyword. The Exception type has been
declared followed by an identifier in which the thrown Exception object would be received
just like the way a method receives arguments in its parameters. We will see later on how
we can use this Exception object to display the error that has occurred and also print the
stack trace. For now, the type is provided only to target the catch block to be executed for
that Exception. We have no intention to use the object to retrieve details of the Exception
that has occurred.
import java.util.Scanner;
import java.util.InputMismatchException;
public class TakeInput {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
try {
System.out.print("Enter an integer: ");
int num = s.nextInt();
System.out.println("You entered " + num);
} catch (InputMismatchException e) {
System.out.println("You have entered invalid data");
}
}
}
Note that the import declaration has been modified to import InputMismatchException as
well since we have used that class type in our catch statement. If you prefer to do so, you
might import the entire package as well. We have provided only a catch block and no finally
block. Run the above program and see the output. When you enter a valid integer, the
program works normally.
Enter an integer: 34
You entered 34
420
In the other case, the statement which displays the accepted integer is skipped in the try
block and the string "You have entered invalid data" is printed.
Enter an integer: Java
You have entered invalid data
Modify the above code and include a finally block also, in addition to the try and catch
blocks.
// try and catch blocks
finally {
System.out.println("Finally is always executed");
}
Run the program, first providing an int as the input value and then providing a String or a
float (anything other than an int). You will notice that the finally block is always executed.
Now modify the program to remove the catch block. Our program now contains only a try
and a finally block. Execute the program. When you give an integer as the input, the output
appears fine. Now, when you give an invalid input, a part of the try block is executed
followed by the finally block. In addition, the stack trace is also printed similar to what we
have seen when no Exception handling was provided. The reason is that even though we
have provided Exception handling statements, we haven't caught the exception. If a try
catch finally sequence doesn't catch an exception, the exception is rethrown. If these set of
try catch finally statements are enclosed within another set of try catch finally blocks, control
moves to the catch blocks of that set. Since, in this case, there were no nested blocks; the
exception was handled by the default exception handler. You will notice a similar output if
you provide catch blocks that cannot handle the InputMismatchException. For instance,
provide a catch block for ArithmeticException. This is thrown in certain situations like
dividing an integer with zero, finding the square root of a number. This exception is a part of
java.lang package. Hence, we need not import it. You will notice that the output still remains
the same. This is because, InputMismatchException was still not handled.
// try
catch ( ArithmeticException e ) {
System.out.println("ArithmeticException handled");
}
// finally
Now modify the code again and replace the ArithmeticException with Exception. This is the
superclass of all Exception types.
//try
catch ( Exception e ) {
421
System.out.println("Exception handled");
}
//finally
When you provide a String as an input, you will see in the output that this particular catch
block was executed. This is because an InputMismatchException is an Exception ( 'is a '
relationship as InputMismatchException is a subclass of Exception) In other words, a
particular catch block is executed if on operating the thrown object with the instanceof
operator and the type stated in the catch clause returns true. This means that we can also
specify an interface as a type. However, there is an Exception as to what type can be
specified. Only classes that implement the Throwable interface can be specified in the catch
clause. Define a catch clause with a String type and you will receive compilation errors. The
Throwable interface is an empty interface. It doesn't contain any methods to be implement.
It is a implemented by a class to simply state that one can catch or throw objects of that
type and the object represents an Exception.
Now, lastly modify the code to include only the try block with no catch or finally blocks. You
will receive compilation errors as a try block needs to be followed by atleast a single catch
or a finally block.
The following example shows how exception handling can be used along with loops to
repeatedly ask the user to enter some data until he enters the required type. In this
example, the program asks for an integer. If the user enters some other data of some other
type, a message is displayed and the programs asks for new input.
public class TakeInput {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
boolean success = false;
while (!success) {
try {
System.out.print("Enter an integer: ");
int num = s.nextInt();
System.out.println("You entered " + num);
success = true;
} catch (InputMismatchException e) {
s.next();
System.out.println("You have entered invalid data");
}
}
}
}
422
Note that within the catch block, we have included the statement, s.next(). This is because
the input stream still contains an invalid data ( date other than int ). To ignore this data, we
read it as a word. If the user has entered multiple words, each of these words would be
ignored in the subsequent iterations. Here is a sample execution.
Enter an integer: java
You have entered invalid data
Enter an integer: 34793479347934793479
You have entered invalid data
Enter an integer: java programming
You have entered invalid data
Enter an integer: You have entered invalid data
Enter an integer: 347
You entered 347
Exception Hierarchy
In the previous chapter, we have seen that an InputMismatchException can be caught by a
catch block defined to handle an exception of type 'Exception' since
InputMismatchException is a subclass of Exception. It is important to know the hierarchy of
exception classes in order to write correct programs. The class Exception lies at the root of
the exception hierarchy. Every exception type in Java is a subclass of Exception. Therefore,
a catch clause designed to handle Exception can process all pre-defined exceptions of
Java. However, in addition to the subclasses of Exception, we have subclasses of Error
which represents a condition that generally cannot be handled by the programmer. The
exceptions that inherit from Error denote serious errors like VirtualMachineError from which
a program cannot normally recover. Though it is syntaxialy correct to catch Errors also, one
however should refrain from doing so. Both, Exception and Error are subclasses of
Throwable. (We have both Throwable class and Throwable interface).
A number of other Exceptions are extended from class Exception. We can group them into
two categories. We can put the Runtime Exception into one category and all other
exceptions in the other category. We will see shortly why we have grouped them in this
way. The following diagram shows this hierarchy.
423
Java distinguishes between checked and unchecked exceptions. Checked exceptions are
those Exceptions for which we need to provide exception handling while unchecked
exceptions are those for which providing exception handlers is optional. You may know the
types of exceptions that would be thrown by looking at the documentation for the method
that you are calling. For example, when we are calling the nextInt() method to take an
integer input from the keyboard, we should also be having an idea of the exceptions that it
might throw. Look at the documentation for this method. You will see that three types of
Exceptions may be thrown by this method. Even when we have not provided exception
handlers for these three methods, the compiler as not raised any objection. This is because;
these three Exceptions are unchecked exception. All exceptions of type
RunTimeExcepotion or its subclasses are considered to be unchecked Exceptions. And , all
exceptions of type Exception other than RunTimeExcepotion are checked exceptions.
Checked exceptions should be either caught or be declared to be thrown. We shall see
shortly how we may throw exceptions instead of catching them.
Here are a few Exceptions that you should be familiar with:
424
425
// code
}
426
Such nesting of try catch blocks can also occur in case of method calls. Nesting may not be
very explicit in such cases. Look at the following example which contains two methods
main() and meth(). Both the methods have exception handlers. meth() is invoked from the
method main(). The try block in meth() throws an ArithmeticException which it could not
handle. Hence, it is rethrown. This try catch sequence of meth() in nested within the try
catch sequence of main() by way of method call. Therefore, the exception is processed by
the finally block of the main() method.
public class Nested {
public static void main(String[] args) {
try {
meth();
} catch (ArithmeticException e) {
System.out.println("ArithmeticException caught");
} finally {
System.out.println("Outer finally");
}
}
public static void meth() {
try {
int res = 3 / 0;
} finally {
System.out.println("Finally in meth");
}
}
}
The output is
Finally in meth
ArithmeticException caught
Outer finally
Throwing Exceptions
We have seen till now how exceptions thrown by methods we invoke such as nextInt() can
be caught. We shall now see how we ourselves can throw exceptions. An exception is
thrown by specifying the throw keyword followed by an object reference.
throw <object>;
427
Only objects that have been created from classes which have implemented the Throwable
interface can be thrown. An object of an Exception can be created just like any other object
of a class by using one of the four forms of the constructor, which every Exception type
inherits from the Throwable class. We shall see two of them for now. One of these is the
default constructor and the other is the parameterised constructor which accepts a String
which acts as a description for the exception object we are creating. The following
statement shows the use of these two forms of the constructor to create an Exception
object.
Exception e = new Exception();
Exception e = new Exception ( "This is an Exception");
The objects created above may be thrown by using the throw keyword.
throw e;
We can also combine the statement that creates the Exception and the statement which
throws the Exception into a single statement.
throw new Exception();
The following program shows the use of the throw keyword.
public class ThrowException {
public static void main(String args[]){
try{
throw new Exception();
} catch(Exception e) {
System.out.println("Exception caught");
}
}
}
The output of this program would be
Exception caught
JAVA PROGRAMMS
Reversing a Number
We will see three different ways of reversing a number.
428
429
430
constructed using the String. These two steps can be combined into a single step in the
following way:
StringBuffer s = new StringBuffer(n+"");
However, the following statement will give incorrect results.
StringBuffer s = new StringBuffer(n);
This is because the constructor of StringBuffer requires a String as its input from which the
StringBuffer is to be constructed. If an integer is passed as an input, that integer would be
taken as the initial length of the StringBuffer.
The integer n concatenated with an empty String results in a String which is passed to the
constructor of StringBuffer. The reverse() process is then invoked on the StringBuffer object
which will reverse its contents. Now, the StringBuffer is converted back to a String and then
to an int using toString() and parseInt() methods respectively.
We can also use the StringBuilder class instead of the StringBuffer class. The difference
between these two classes is that StringBuffer is synchronised while StringBuilder is not.
Here is the complete method illustrating the above procedure.
public static int reverse(int n) {
String inputString = String.valueOf(n);
StringBuffer stringBuffer = new StringBuffer(inputString);
stringBuffer.reverse();
String reversedString = stringBuffer.toString();
int reversedInt = Integer.parseInt(reversedString);
return reversedInt;
}
Prime Numbers
A prime number has only two factors, namely one and itself. To determine whether a given
number is prime, we need to check if it has factors others than one and itself. If we are able
to find atleast one other factor, then we can conclude that the number is not prime. To
check if a number is a factor of the given number ( hereafter referred to as n ), we obtain the
remainder on dividing n by the number. If the remainder is zero, then the number is a
factor.
The next question is what is the range of numbers we need to consider while checking if
they are factors? Since, a number is definitely not divisible by any number greater than
itself, we can place n as the upper limit. We can further reduce this upper limit by noting that
431
a number has no other factors ( except itself ) greater than sqrt(n). To sum up, within a loop,
we find the remainder on dividing the number n with the loop counter which ranges from 2
to sqrt(n). If at any time, we get the remainder as zero, we conclude that the number is not
prime. Special checks should be used for the number one, which is neither prime nor
composute. If necessary, additional checks can be done for negative numbers.
Here is a method which takes an integer n as an input and returns true or false, depending
on whether the number is prime or not.
public boolean isPrime(int n) {
if (n <= 1) {
return false;
}
for (int i = 2; i < Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
Here is a complete Java programs which accepts a number from the user, checks if the
number is prime and displays the result on the screen.
import java.util.Scanner;
public class PrimeNumbers {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Enter a number : ");
int n = s.nextInt();
if (isPrime(n)) {
System.out.println(n + " is a prime number");
} else {
System.out.println(n + " is not a prime number");
}
}
public static boolean isPrime(int n) {
if (n <= 1) {
return false;
}
for (int i = 2; i < Math.sqrt(n); i++) {
432
if (n % i == 0) {
return false;
}
}
return true;
}
}
Here are two sample executions of the above program.
Enter a number : 7
7 is a prime number
Enter a number : 34
34 is not a prime number
Here is a program which takes two numbers as input from the user and prints all the prime
numbers that lie between these two numbers.
import java.util.Scanner;
public class PrimeNumbers {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Enter the first number number : ");
int start = s.nextInt();
System.out.print("Enter the second number number : ");
int end = s.nextInt();
System.out.println("List of prime numbers between " + start + " and " + end);
for (int i = start; i <= end; i++) {
if (isPrime(i)) {
System.out.println(i);
}
}
}
public static boolean isPrime(int n) {
if (n <= 1) {
return false;
}
for (int i = 2; i < Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
433
}
}
return true;
}
}
Here is a sample run of the above program:
Enter the first number number : 2
Enter the second number number : 10
List of prime numbers between 2 and 10
2
3
4
5
7
9
434
Given below is an example illustrating the conversion of a String to the five different cases
mentioned above.
HeLLo java. hello WORlD.
Upper Case: HELLO JAVA. HELLO WORLD.
Lower Case: hello java. hello world.
Toggle Case: hEllO JAVA. HELLO worLd.
Camel Case: Hello Java. Hello World.
Title Case: Hello java. Hello world.
435
To convert a String to Upper Case, we use a for loop whose counter, say i, runs from 0
through the length of the String (-1). A String variable 'result' is initialised with an empty
String. Within the loop, we extract the character at position i, convert it to an upper case
character using the toUpperCase () method and append the returned char to the result. At
the end of the loop, the result contains the input string with all characters changed to upper
case. Scroll down to the bottom of this page to the method toUpperCase() to view the code.
436
The Program
437
Given below is a complete program which takes an input String from the user, converts it
into different cases and displays them on the console.
import java.util.Scanner;
public class CaseManipulation {
public static String toUpperCase(String inputString) {
String result = "";
for (int i = 0; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
char currentCharToUpperCase = Character.toUpperCase(currentChar);
result = result + currentCharToUpperCase;
}
return result;
}
public static String toLowerCase(String inputString) {
String result = "";
for (int i = 0; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
char currentCharToLowerCase = Character.toLowerCase(currentChar);
result = result + currentCharToLowerCase;
}
return result;
}
public static String toToggleCase(String inputString) {
String result = "";
for (int i = 0; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
if (Character.isUpperCase(currentChar)) {
char currentCharToLowerCase = Character.toLowerCase(currentChar);
result = result + currentCharToLowerCase;
} else {
char currentCharToUpperCase = Character.toUpperCase(currentChar);
result = result + currentCharToUpperCase;
}
}
return result;
}
public static String toCamelCase(String inputString) {
String result = "";
438
if (inputString.length() == 0) {
return result;
}
char firstChar = inputString.charAt(0);
char firstCharToUpperCase = Character.toUpperCase(firstChar);
result = result + firstCharToUpperCase;
for (int i = 1; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
char previousChar = inputString.charAt(i - 1);
if (previousChar == ' ') {
char currentCharToUpperCase = Character.toUpperCase(currentChar);
result = result + currentCharToUpperCase;
} else {
char currentCharToLowerCase = Character.toLowerCase(currentChar);
result = result + currentCharToLowerCase;
}
}
return result;
}
public static String toSentenceCase(String inputString) {
String result = "";
if (inputString.length() == 0) {
return result;
}
char firstChar = inputString.charAt(0);
char firstCharToUpperCase = Character.toUpperCase(firstChar);
result = result + firstCharToUpperCase;
boolean terminalCharacterEncountered = false;
char[] terminalCharacters = {'.', '?', '!'};
for (int i = 1; i < inputString.length(); i++) {
char currentChar = inputString.charAt(i);
if (terminalCharacterEncountered) {
if (currentChar == ' ') {
result = result + currentChar;
} else {
char currentCharToUpperCase = Character.toUpperCase(currentChar);
result = result + currentCharToUpperCase;
terminalCharacterEncountered = false;
}
} else {
char currentCharToLowerCase = Character.toLowerCase(currentChar);
result = result + currentCharToLowerCase;
}
439
440
Now, our task is to multiply the variable result with all natural numbers from 1 to n. For this
purpose, we use a for loop with a counter i that ranges from 1 to n. Within the loop, the
existing value of result will be multiplied with the loop counter.
for (int i = 1; i <= n; i++) {
result = result * i;
}
Let us take a small number n = 3 to understand how the above loop works. Before entering
the loop, result would be initialised to one. The loop will execute thrice with the value of i =
1, 2 and 3. When the value of i becomes 4, the loop condition fails. When the value of i is 1,
the existing result would be multiplied with 1 which again gives one. In the second iteration,
result will be multiplied with 2 and in the third iteration with 3. These calculations are shown
below:
result = 1
i = 1 result = result * i = 1 * 1 = 1
i = 2 result = result * i = 1 * 2 = 2
i = 3 result = result * i = 2 * 3 = 6
When the loop exists, the value result which was initially one would be already multiplied by
all natural numbers from 1 to n. Thus, result holds the factorial of the number.
Given below is a program which finds the factorial of the number 7.
public class Factorial {
public static void main(String[] args) {
int n = 7;
int result = 1;
for (int i = 1; i <= n; i++) {
result = result * i;
}
System.out.println("The factorial of 7 is " + result);
}
}
The output of the above program would be
The factorial of 7 is 5040
We can start the loop counter, i from 2 instead of 1 because in the first iteration the value of
result gets multiplied by 1 which again gives one. The modified loop can be written as
441
442
The factorial of a number be found using recursion also. The base case can be taken as the
factorial of the number 0 or 1, both of which are 1. The factorial of some number n is that
number multiplied by the factorial of (n-1). Mathematically,
factorial ( 0 ) = 1
factorial ( n ) = n * factorial ( n - 1 )
Given below is a program which calculates the factorial of 7 using recursion.
public class Factorial {
public static void main(String[] args) {
int n = 7;
int result = factorial(n);
System.out.println("The factorial of 7 is " + result);
}
public static int factorial(int n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
}
443
444
445
446
of the String class. The length of the resultant string obtaining using the length() method will
give us the number of digits in the input number.
We also declare a variable sum and initialise it to zero. This variable will hold the sum of the
digits raised to the appropriate powers.
Next, in a while loop, we extract the digits of the input from right to left, raise them to the
appropriate power and add to the existing value of sum. To extract the last digit of the
number, we find the remainder obtained don dividing that number by 10 using the modulo
operator. The remainder is raised to the power numberOfDigits using the Math.pow()
function. This function returns a double value which we explicitly cast to an int so that we
can add it to the existing sum. Now, the last digit of copyOfInpuit will be truncated by diving
it with 10. The while loop executes as long as copyOfInput is not zero. When it is zero, all
the digits would have been processed.
Finally, we check if sum equals the input number. If it is so, the number is an Armstrong
number. Given below is the complete code for this program.
import java.util.Scanner;
public class ArmstrongNumber {
public static boolean isArmstrong(int input) {
String inputAsString = input + "";
int numberOfDigits = inputAsString.length();
int copyOfInput = input;
int sum = 0;
while (copyOfInput != 0) {
int lastDigit = copyOfInput % 10;
sum = sum + (int) Math.pow(lastDigit, numberOfDigits);
copyOfInput = copyOfInput / 10;
}
if (sum == input) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter a number: ");
int inputNumber = scanner.nextInt();
447
448
449
number of columns of the matrix. For example, a matrix of order 3*7 will be represented as
a 2D array matrix[3][7]. A two level nested for loop will be used to read the input matrices
from the keyboard. The outer loop counter, i ranges from 0 to the number of rows of the
matrix while the inner loop counter, j ranges from 0 to the number of columns of the matrix.
Within the inner loop, the input integers will be read using nextInt() method of the scanner
class and stored at position [i][j] of the array.
Once the two matrices are read, we use a two level nested for loop with loop counters
similar to the ones used for adding the matrices. The elements at [i][j] of the two input
matrices are added and the result is stored at position [i][j] of the result matrix. For
subtraction, the same procedure is followed except that we subtract the elements at [i][j]
instead of adding them.
Finally, we print the matrices using a nested for loop. We wish to print the array in the form
of a rectangular matrix. For this purpose, we use print() instead of println() for displaying the
values within the inner loop. At the end of the inner loop, we use a println() statement
without any arguments to move to the next line.
The complete Java program for addition of two matrices is given below.
import java.util.Scanner;
public class MatrixAddition {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.print("Enter number of rows: ");
int rows = s.nextInt();
System.out.print("Enter number of columns: ");
int columns = s.nextInt();
int[][] a = new int[rows][columns];
int[][] b = new int[rows][columns];
System.out.println("Enter the first matrix");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
a[i][j] = s.nextInt();
}
}
System.out.println("Enter the second matrix");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
b[i][j] = s.nextInt();
}
450
}
int[][] c = new int[rows][columns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
c[i][j] = a[i][j] + b[i][j];
}
}
System.out.println("The sum of the two matrices is");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
System.out.print(c[i][j] + " ");
}
System.out.println();
}
}
}
Here is a sample execution.
Enter number of rows: 2
Enter number of columns: 3
Enter the first matrix
347
184
Enter the second matrix
321
104
The sum of the two matrices is
668
288
For subtraction, the plus sign in line 'c[i][j] = a[i][j] + b[i][j];' should be changed to a minus
sign.
In the above program, a lot of code was repetitive in nature. We have used the same code
to read the two matrices. If both addition and subtraction are to be performed, the code for
printing the matrices will also be duplicated twice. Instead of writing the same code a
number of times, we can use methods. Given below is a modified version of the previous
program which takes two input matrices A and B and performs three operations, A+B, A-B,
B-A.
import java.util.Scanner;
public class Matrices {
451
452
453
46
10 13
A-B=
22
45
B-A=
-2 -2
-4 -5
454
455
}
}
Here is a sample execution of the above program.
Enter number of rows in A: 2
Enter number of columns in A / rows in B: 3
Enter number of columns in B: 3
Enter matrix A
134
256
Enter matrix B
156
254
111
Product of A and B is
11 24 22
18 41 38
456
Towers of Hanoi
The 'Towers of Hanoi' is a classical problem used to illustrate the power of recursion. The
puzzle goes as follows.
There are three poles and 64 discs of different sizes. Initially, all the discs are placed on the
first pole with the largest disc at the bottom and the smallest one at the top. We need to
457
move all the discs from the first pole to the third pole, with the smallest disc at the top and
the largest at the bottom. We can move only one disc at a time (which should be the
topmost disc) and at any point of time, a larger disc cannot be placed over a smaller one i.e.
all the discs on a pole must be placed in such a way that the smallest is at the top and the
largest at the bottom. The second pole can be used as an intermediate pole to help us in
transferring the discs.
This puzzle can be solved using recursion. For a moment, assume that there are just two
discs (disc 1 and 2; disc 2 being the larger one) on the first pole. The solution consists of
three steps.
Step
Step
Step
1:
2:
3:
Move
Move
Move
disc
disc
disc
1
2
1
from
from
from
pole
pole
pole
1
1
1
to
to
to
pole
pole
pole
2.
3.
3.
Now, assume that disc 1 is not a single disc but a collection of discs. The procedure would
be similar to the above three steps, but steps 1 and 3 would be a collection of steps. Step 1
would be to move the n-1 discs (assuming that there were a total of n discs) from pole 1 to
pole 2. For moving these (n -1) discs, we again follow the same strategy of considering
them as 1 disc plus a set of n-2 discs. Step 3 would also be similar. This gives us the
recursive solution.
Recursive Algorithm
The recursive solution to move n discs from the start pole to the end pole using an auxiliary
pole is given below.
Base
Case
Move the disc from start pole to end pole
When
Recursive
Case
When
n
Step
1:
Move
(n-1)
discs
from
start
pole
to
Step
2:
Move
the
last
disc
from
start
pole
Step
3:
Move
the
(n-1)
discs
from
auxiliary
pole
Steps 1 and 3 are recursive invocations of the same procedure.
Java Program
The recursive program for the puzzle in Java is given below:
public class TowersOfHanoi {
>
auxiliary
to
end
to
end
1
pole.
pole.
pole.
458
Next we print ' start -> end ' which corresponds to moving the largest disc at the bottom
from the start peg to the end peg.
Finally, we have recursive invocation of solve(). Here, the auxiliary peg becomes the start
peg and the start peg becomes the auxiliary peg.
Here is a sample output with n = 3.
459
Pascal's Triangle
This article intends to show the different ways to print a Pascal's triangle and also format it
so that it looks like an isosceles triangle.
Understanding how a Pascal's triangle is built would be easier by considering the following
figure which shows the first six rows of the Pascal's triangle.
1
11
121
1331
14641
1 5 10 10 5 1
Each row begins and ends with the number one. The remaining numbers are obtained by
summing the two numbers that lie directly above that number on the previous row and the
number that follows it. So, in order to find the numbers in the nth row of the triangle, we
need the values of the (n-1) the row. Let's say that we have computed the fourth row - 1 3 3
1. Now, the fifth row has five elements. The first and the last element would be one. The
remaining elements would be (1+3), (3+3), (3+1) = 4, 6, 4. So, the complete fifth row would
be 1 4 6 4 1.
460
the result is stored at the index j+1 of currentRow. When the inner loop exits, currentRow
would be populated. The values stored in currentRow are printed and previousRow is
assigned with currentRow so that it can be used in the next iteration of the outer loop.
Given below is a complete program which takes an input n from the user and prints the first
n lines of the Pascal's triangle.
import java.util.Scanner;
public class PascalTriangle {
public static void print(int n) {
int[] previousRow;
int[] currentRow = {1};
printArray(currentRow);
previousRow = currentRow;
for (int i = 2; i <= n; i++) {
currentRow = new int[i];
currentRow[0] = 1;
currentRow[i - 1] = 1;
for (int j = 0; j <= i - 3; j++) {
currentRow[j + 1] = previousRow[j] + previousRow[j + 1];
}
printArray(currentRow);
previousRow = currentRow;
}
}
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the row number upto which Pascal's triangle has to be printed:
");
int row = scanner.nextInt();
print(row);
}
}
461
462
463
}
}
public static int pascal(int i, int j) {
if (j == 0) {
return 1;
} else if (j == i) {
return 1;
} else {
return pascal(i - 1, j - 1) + pascal(i - 1, j);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the row number upto which Pascal's triangle has to be printed:
");
int row = scanner.nextInt();
print(row);
}
}
Procedure
First, let us see how humans perform the computation. We start with the given decimal
number, and repeatedly divide it by 2 (whole number division where the result will be only
the quotient, a whole number) and note down the remainder at every step till we obtain the
quotient as 0. The remainders obtained in each step when concatenated together (the last
remainder taken as the first digit of the binary number) give the binary form of the decimal
number.
Shown below is the repeated division of 14.
464
The remainders obtained when concatenated together give the binary representation of 14
which is 1110.
Java Program
The program is given below. The explanation follows it.
import java.util.Scanner;
public class DecimalToBinary {
public String toBinary(int n) {
if (n == 0) {
return "0";
}
String binary = "";
while (n > 0) {
int rem = n % 2;
binary = rem + binary;
n = n / 2;
}
return binary;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
465
466
Sieve of Eratosthenes
The sieve of Eratosthenes is an efficient method for computing primes upto a certain
number. We first look at the algorithm and then give a program in Java for the same.
Algorithm
If you want to calculate all the primes up to x, then first write down the numbers from 2 to x.
Remove the first number from this list (say y) and add it to the list of primes. Find all the
multiples of y (excluding y) less than or equal to x and remove them out from the list.
Repeat the above process until there you are left with no numbers.
We illustrate this procedure by finding all primes less than 15. (To indicate removal of an
item from the list, we simply strike it out and to indicate addition of a number to the primes
list, we put a tick mark over it)
First, we write down all the numbers from 2 to 15.
Iteration 1: Select the first number, 2. The multiples of 2 less than or equal to 15 are 4, 6, 8,
10, 12 and 14. We strike them out to indicate that they are not primes and mark 2 as a
prime by keeping a tick mark over it.
Iteration 2: Now, we select the next number, 3. We again strike out the multiples of 3 less
than or equal to 15 which are - 6, 9, 12, 15. Note that 6 and 12 have already been crossed
out. If you want, you can strike them out again. It wouldn't make any difference to the final
result but there is no need of doing so. However, when we implement the program in Java,
you will see that we do strike out these numbers a second time ( by setting a flag to false
which is already false) which is simpler than first checking if it is already struck out ( the flag
already set to false ). We also put a tick mark over 3 to indicate that it is a prime number.
467
Iteration 3: The number 5 is selected. The multiples of 5 are 10 and 15 which are already
struck out. 5 is marked as a prime.
Iteration 4: 7 is selected. Here too, its only multiple 14 is already struck out. 7 is marked as
a prime number.
Iteration 6: 13 is selected. As was the case with 11, 13 too doesn't have any multiples in
the list we are considering. We just mark 13 as a prime.
There are no more numbers left. So, the process stops. We have obtained 2, 3, 5, 7, 11 and
13 as the primes up to 15.
Implementation in Java
Following is the Java program for Sieve of Eratosthenes.
import java.util.Scanner;
public class SieveOfEratosthenes {
public void primes(int n) {
boolean[] primes = new boolean[n + 1];
for (int i = 2; i < primes.length; i++) {
primes[i] = true;
}
468
int num = 2;
while (true) {
for (int i = 2;; i++) {
int multiple = num * i;
if (multiple > n) {
break;
} else {
primes[multiple] = false;
}
}
boolean nextNumFound = false;
for (int i = num + 1; i < n + 1; i++) {
if (primes[i]) {
num = i;
nextNumFound = true;
break;
}
}
if (!nextNumFound) {
break;
}
}
for (int i = 0; i < primes.length; i++) {
if (primes[i]) {
System.out.println(i);
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter a number: ");
int n = scanner.nextInt();
SieveOfEratosthenes sieve = new SieveOfEratosthenes();
sieve.primes(n);
}
}
The method sieve() accepts a parameter n up to which primes are to be calculated. We
create a boolean array names primes of size (n+1) and set all the values (except 0 and 1) to
true i.e. initially, we consider all numbers from 0 to n as primes (indicated by the boolean
value true) As the execution proceeds, some of these true false will be changed to false to
indicate that they are not primes. primes[i] tells us whether the number i is a prime or not.
469
We have a variable num to hold the current number we are considering i.e. the number
whose multiples we are finding out. num is initially set to 2.
The while loop has two parts. In the first part, we find all the multiples of num up to n and
set primes[multiple] to false. The multiples are found by multiply the number num with 2, 3,
4... in the for loop. If the multiple obtained is less than n, then it is present in the list we are
considering and so we set primes[multiple] to false. If not, then it means that, we have
crossed the limit n and so, we break out of the loop.
In the second part, we find the number which we will be considering in the next iteration of
the while loop i.e. we find a new value for num. To do so, we use a for loop with its loop
counter ranging from num+1 to n (inclusive) and check if primes[i] is true. If so, i is the next
value for num. At the end of the loop if no value is found for num (indicated with a value of
false for the variable nextNumFound), then it means that we have finished checking all the
numbers and so, we break out of the for loop.
Finally, we print the primes.
Here is a sample run of the program.
Enter a number: 13
2
3
5
7
11
13
Here is an example:
// Using concatenation to prevent long lines.
470
class ConCat {
public static void main(String args[]) {
String longStr = "This could have been " +
"a very long line that would have " +
"wrapped around. But string concatenation " +
"prevents this.";
System.out.println(longStr);
}
}
String Concatenation with other Data Types
You can concatenate strings with other types of data. For example, consider this slightly different
version of the earlier example:
int age = 9;
String s = "He is " + age + " years old.";
System.out.println(s);
In this case, age is an int rather than another String, but the output produced is the same as before.
This is because the int value in age is automatically converted into its string representation within
aString object. This string is then concatenated as before. The compiler will convert an operand to
its string equivalent whenever the other operand
of the + is an instance of String. Be careful when you mix other types of operations with string
concatenation expressions, however. You might get surprising results. Consider the following:
String s = "four: " + 2 + 2;
System.out.println(s);
This fragment displays
four: 22
rather than the
four: 4
that you probably expected. Here's why. Operator precedence causes the concatenation of "four"
with the string equivalent of 2 to take place first. This result is then concatenated with the string
equivalent of 2 a second time. To complete the integer addition first, you must use parentheses, like
this:
String s = "four: " + (2 + 2);
Now s contains the string "four: 4".
This tutorial demonstrates using string array in Java. Here, you will see how to declare a string
array and the syntax for using in the program.
Following code of the program declares a string array and stores some strings of first names like
"Lee", "Freddy", "Dorris", "Mary", and "Anne" to it. And in the main method these string are displayed
one by one by retrieving from the specified string array namedfirstnames. In this program all the
string values are stored in thefirstnamesstring array at the declaration time.
471
Sample Code:
class StringCharacter
{
static String[] firstnames={"Lee", "Freddy", "Dorris", "Mary","Anne"};
public static void main(String args[]){
for(int i=0;i<5;i++){
System.out.println(firstnames[i]);
}
}
}
Output of program:
C:\>javac StringCharacter.java
C:\>java StringCharacter
Lee
Freddy
Dorris
Mary
Anne
C:\>
if (pal.length() <= 1) {
// String has only one character so it
// is a Palindrome by definition.
472
return true;
// BASE CASE.
if (Character.isLetter(first) &&
Character.isLetter(last)) {
// The first and last characters are both letters..
if (first != last) {
// The first and last letters are different
// so the string is not a Palindrome.
return false;
// BASE CASE.
}
else {
// The first and last characters are both letters,
// and they are both the same. So, the string is
// a palindrome if the substring created by dropping
// the first and last characters is a palindrome.
Palindrome sub = new Palindrome(
pal.substring(1,pal.length()-1));
473
return sub.isPalindrome();
// RECURSIVE CASE.
}
}
else if (!Character.isLetter(first)) {
// The first character in the string is not a letter.
// So the string is a palindrome if the substring created
// by dropping the first character is a palindrome.
Palindrome sub = new Palindrome(pal.substring(1));
return sub.isPalindrome();
// RECURSIVE CASE.
}
else {
// The last character in the string is not a letter.
// So the string is a palindrome if the substring created
// by dropping the last character is a palindrome.
Palindrome sub = new Palindrome(
pal.substring(0,pal.length()-1));
return sub.isPalindrome();
// RECURSIVE CASE.
}
}
474
System.out.println(p1.isPalindrome());
Palindrome p2 = new Palindrome("Nope!");
System.out.println(p2.isPalindrome());
Palindrome p3 = new Palindrome("dad");
System.out.println(p3.isPalindrome());
Palindrome p4 = new Palindrome("Go hang a salami, I'm a lasagna
hog.");
System.out.println(p4.isPalindrome());
}
}
475
The trim( ) method is quite useful when you process user commands. For example, the following
program prompts the user for the name of a state and then displays that state's capital. It uses trim(
)to remove any leading or trailing whitespace that may have inadvertently been entered by the user.
// Using trim() to process commands.
import java.io.*;
class UseTrim {
public static void main(String args[])
throws IOException
{
// create a BufferedReader using System.in
BufferedReader br = new
BufferedReader(new InputStreamReader(System.in));
String str;
System.out.println("Enter 'stop' to quit.");
System.out.println("Enter State: ");
do {
str = br.readLine();
str = str.trim(); // remove whitespace
if(str.equals("Illinois"))
System.out.println("Capital is Springfield.");
else if(str.equals("Missouri"))
System.out.println("Capital is Jefferson City.");
else if(str.equals("California"))
System.out.println("Capital is Sacramento.");
else if(str.equals("Washington"))
System.out.println("Capital is Olympia.");
// ...
} while(!str.equals("stop"));
}
}
476
char chars[] = { 'a', 'b', 'c' };
String s = new String(chars);
This constructor initializes s with the string "abc".
You can specify a subrange of a character array as an initializer using the following constructor:
String(char chars[ ], int startIndex, int numChars)
Here, startIndex specifies the index at which the subrange begins, and numChars specifies the
number of characters to use. Here is an example:
char chars[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
String s = new String(chars, 2, 3);
This initializes s with the characters cde.
You can construct a String object that contains the same character sequence as
another String object using this constructor:
String(String strObj)
Here, strObj is a String object. Consider this example:
// Construct one String from another.
class MakeString {
public static void main(String args[]) {
char c[] = {'J', 'a', 'v', 'a'};
String s1 = new String(c);
String s2 = new String(s1);
System.out.println(s1);
System.out.println(s2);
}
}
The output from this program is as follows:
Java
Java
As you can see, s1 and s2 contain the same string.
Even though Java's char type uses 16 bits to represent the Unicode character set, the typical format
for strings on the Internet uses arrays of 8-bit bytes constructed from the ASCII character set.
Because 8-bit ASCII strings are common, the String class provides constructors that initialize a
string when given a byte array. Their forms are shown here:
String(byte asciiChars[ ])
String(byte asciiChars[ ], int startIndex, int numChars)
Here, asciiChars specifies the array of bytes. The second form allows you to specify a subrange. In
each of these constructors, the byte-to-character conversion is done by using the default character
encoding of the platform. The following program illustrates these constructors:
// Construct string from subset of char array.
class SubStringCons {
public static void main(String args[]) {
byte ascii[] = {65, 66, 67, 68, 69, 70 };
String s1 = new String(ascii);
System.out.println(s1);
String s2 = new String(ascii, 2, 3);
System.out.println(s2);
}
}
This program generates the following output:
ABCDEF
CDE
Extended versions of the byte-to-string constructors are also defined in which you can specify the
character encoding that determines how bytes are converted to characters. However, most of the
time, you will want to use the default encoding provided by the platform.
477
Note: The contents of the array are copied whenever you create
a Stringobject from an array. If you modify the contents of the array
after you have created the string, theString will be unchanged.
478
479
str = br.readLine();
480
481
}
}
Here is the output of this program:
Now is the time for all good men to come to the aid of their country.
indexOf(t) = 7
lastIndexOf(t) = 65
indexOf(the) = 7
lastIndexOf(the) = 55
indexOf(t, 10) = 11
lastIndexOf(t, 60) = 55
indexOf(the, 10) = 44
lastIndexOf(the, 60) = 55
482
Hello equals HELLO -> false
Hello equalsIgnoreCase HELLO -> true
483
484
class ChangeCase {
public static void main(String args[])
{
String s = "This is a test.";
System.out.println("Original: " + s);
String upper = s.toUpperCase();
String lower = s.toLowerCase();
System.out.println("Uppercase: " + upper);
System.out.println("Lowercase: " + lower);
}
}
The output produced by the program is shown here:
Original: This is a test.
Uppercase: THIS IS A TEST.
Lowercase: this is a test.
valueOf() in Java
The valueOf( ) method converts data from its internal format into a human-readable form. It is a static
method that is overloaded within String for all of Java's built-in types, so that each type can be converted
properly into a string. valueOf( ) is also overloaded for type Object, so an object of any class type you
create can also be used as an argument. (Recall that Object is a superclass for all classes.) Here are a
few of its forms:
static String valueOf(double num)
static String valueOf(long num)
static String valueOf(Object ob)
static String valueOf(char chars[ ])
As we discussed earlier, valueOf( ) is called when a string representation of some other type of data
is neededfor example, during concatenation operations. You can call this method directly with any
data type and get a reasonable String representation. All of the simple types are converted to their
commonString representation. Any object that you pass to valueOf( ) will return the result of a call
to the object's toString( ) method. In fact, you could just call toString( ) directly and get the same
result.
For most arrays, valueOf( ) returns a rather cryptic string, which indicates that it is an array of some
type. For arrays of char, however, a String object is created that contains the characters in
the chararray. There is a special version of valueOf( ) that allows you to specify a subset of
a char array. It has this general form:
static String valueOf(char chars[ ], int startIndex, int numChars)
Here, chars is the array that holds the characters, startIndex is the index into the array of characters
at which the desired substring begins, and numChars specifies the length of the substring.
This Java program defines a class Employee to accept emp_id, emp _name, basic_salary from the
user and display the gross_salary.
485
import java.lang.*;
import java.io.*;
class Employee
{
int emp_id;
String emp_name;
float basic_salary;
Employee(int id, String name, float sal)
{
emp_id=id;
emp_name=name;
basic_salary=sal;
}
void display()
{
float da=basic_salary*15/100;
float hra=basic_salary*10/100;
float gross_sal=basic_salary+da+hra;
System.out.println ("Employee Id= "+emp_id);
System.out.println ("Emplyee Name= "+emp_name);
System.out.println ("Gross Salary= "+gross_sal);
}
486
}
class q4Employee
{
public static void main(String args[]) throws IOException
{
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
System.out.println ("Enter Employee id");
int id = Integer.parseInt(br.readLine());
System.out.println ("Enter Employee Name");
String name = br.readLine();
System.out.println ("Enter Basic Salary");
Float sal = Float.parseFloat(br.readLine());
Employee e = new Employee(id, name, sal);
e.display();
}
}
487
{
public static void main(String args[]) throws IOException
{
double avg;
float sum=0;
float sales[]=new float[7];
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
for(int i=1;i<=7;i++)
{
System.out.println ("Enter sales for day"+i+" of week
=");
sales[i-1] = Float.parseFloat(br.readLine());
sum=sum+sales[i-1];
}
System.out.println ("Sum = "+sum);
avg=sum/7;
System.out.println ("Average sale of week="+avg);
}
}
488
Class Student
Name, roll_no
Mark 1, Mark2
Interface: Exam
Percent_cal( )
Class: Result
Display( )
import java.lang.*;
import java.io.*;
interface Exam
{
void percent_cal();
}
class Student
{
String name;
int roll_no,mark1,mark2;
Student(String n, int r, int m1, int m2)
{
name=n;
roll_no=r;
489
mark1=m1;
mark2=m2;
}
void display()
{
System.out.println ("Name of Student: "+name);
System.out.println ("Roll No. of Student: "+roll_no);
System.out.println ("Marks of Subject 1: "+mark1);
System.out.println ("Marks of Subject 2: "+mark2);
}
}
class Result extends Student implements Exam
{
Result(String n, int r, int m1, int m2)
{
super(n,r,m1,m2);
}
public void percent_cal()
{
int total=(mark1+mark2);
float percent=total*100/200;
System.out.println ("Percentage: "+percent+"%");
490
}
void display()
{
super.display();
}
}
class q10Multiple
{
public static void main(String args[])
{
Result R = new Result("Ra.one",12,93,84);
R.display();
R.percent_cal();
}
}
491
class ArrayCopyDemo {
public static void main(String[] args) {
char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e',
'i', 'n', 'a', 't', 'e', 'd' };
char[] copyTo = new char[7];
492
al.size());
// add elements to the array list
al.add("C");
al.add("A");
al.add("E");
al.add("B");
al.add("D");
al.add("F");
al.add(1, "A2");
System.out.println("Size of al after additions: " +
al.size());
// display the array list
System.out.println("Contents of al: " + al);
// Remove elements from the array list
al.remove("F");
al.remove(2);
System.out.println("Size of al after deletions: " +
al.size());
System.out.println("Contents of al: " + al);
}
}
The output from this program is shown here:
Initial size of al: 0
Size of al after additions: 7
Contents of al: [C, A2, A, E, B, D, F]
Size of al after deletions: 5
Contents of al: [C, A2, E, B, D]
Notice that a1 starts out empty and grows as elements are added to it. When elements are removed,
its size is reduced.
Although the capacity of an ArrayList object increases automatically as objects are stored in it, you
can increase the capacity of an ArrayList object manually by calling ensureCapacity( ). You might
want to do this if you know in advance that you will be storing many more items in the collection that
it can currently hold. By increasing its capacity once, at the start, you can prevent several
reallocations later. Because reallocations are costly in terms of time, preventing unnecessary ones
improves performance. The signature for ensureCapacity( ) is shown here:
void ensureCapacity(int cap)
Here, cap is the new capacity. Conversely, if you want to reduce the size of the array that underlies
anArrayList object so that it is precisely as large as the number of items that it is currently holding,
call
trimToSize( ), shown here:
void trimToSize( )
Obtaining an Array from an ArrayList
493
When working with ArrayList, you will sometimes want to obtain an actual array that contains the
contents of the list. As explained earlier, you can do this by calling toArray( ). Several reasons exist
why you might want to convert a collection into an array such as:
To obtain faster processing times for certain operations.
To pass an array to a method that is not overloaded to accept a collection.
To integrate your newer, collection-based code with legacy code that does not understand
collections.
Whatever the reason, converting an ArrayList to an array is a trivial matter, as the following
program shows:
// get array
Object ia[] = al.toArray();
int sum = 0;
// sum the array
for(int i=0; i<ia.length; i++)
sum += ((Integer) ia[i]).intValue();
System.out.println("Sum is: " + sum);
}
}
The output from the program is shown here:
Contents of al: [1, 2, 3, 4]
Sum is: 10
The program begins by creating a collection of integers. As explained, you cannot store primitive
types in a collection, so objects of type Integer are created and stored. Next, toArray( ) is called and
it obtains an array of Objects. The contents of this array are cast to Integer, and then the values are
summed.