Introduction to Java Programming Language |
Java is a very famous high
level programming language. Java was developed at Sun Microsystems in the early 1990s and
is based on C++. It looks very similar to C++ but it is significantly
simplified as compared to C++. This is the reason why Java is sometimes referred to as C++--. Java is a
pure Object Oriented Programming Language. Everything in Java is an object. Java has eliminated many C++ concepts, like
multiple inheritance, pointers, structs, enum types, operator overloading, goto statement, etc. Java is a platform independent programming language. Without
even a recompile, a Java executable can run on any JVM enabled platform. Java is also
network friendly for its portable and threaded nature and because of its rich
network libraries. Java provides an extensive support for the development
of web and enterprise
applications. Servlets, JSP,
Applets, JDBC, RMI, EJBs and JSF etc. are some of the Java technologies that
are used to build the web and enterprise applications.
Java versus C++:
Generally, Java is more robust than C++. Some of
the reasons are:
·
Object handles are
initialized to null (a keyword)
·
Handles are always
checked and exceptions are thrown for failures
·
All array accesses
are checked for bounds violations
·
Automatic garbage
collection prevents memory leaks and dangling pointers
·
Type conversion is
safer
·
Clean, relatively
fool-proof exception handling
·
Simple language
support for multithreading
·
Bytecode verification
of network applets
Our First Java Program |
In this lesson we will learn to write our first
Java program. Before doing so, let’s first understand some basics of Java
program files.
Java Program Files:
Java program files are very similar to the .c or .cpp program files. In Java the source code is written in the .java file. Each .java source file can contain at most one public class. If there is a public class, then the class name and file name must match. Furthermore, every piece of java code must be the part of a class.
The Java compiler creates Bytecode from the .java program file and stores the same in a .class file. This Bytecode, contained in the .class file, generated by the Java compiler is ready to be executed by the Java Virtual Machine (JVM). For each class in a source file (both public and non-public classes), the compiler creates one ".class" file, where the file name is the same as the class name.
Java Program Files:
Java program files are very similar to the .c or .cpp program files. In Java the source code is written in the .java file. Each .java source file can contain at most one public class. If there is a public class, then the class name and file name must match. Furthermore, every piece of java code must be the part of a class.
The Java compiler creates Bytecode from the .java program file and stores the same in a .class file. This Bytecode, contained in the .class file, generated by the Java compiler is ready to be executed by the Java Virtual Machine (JVM). For each class in a source file (both public and non-public classes), the compiler creates one ".class" file, where the file name is the same as the class name.
Our First Java Program:
Let’s write our first Java program:
Let’s write our first Java program:
class HelloWorld {
public static void main( String [ ] args ) {
System.out.println("Hello
world!");
}
}
You must be glad to see that the above code is very similar
to the C or C++ code. When the above code is run after compilation, it simply
prints “Hello world!” to the console.
Important points to
remember:
·
Function main is the
entry point of a java program.
·
Function main is a
member of the class.
·
Every class MAY have
at most one main function. There may be more than one main function in a Java
program, however.
·
The main function
must be public static void.
·
The main must have
only one argument: an array of String. This array contains the
command-line arguments.
·
There is no final
semi-colon at the end of the class definition.
Compiling a Java Program File:
We assume that you have downloaded and installed the latest version of JDK (Java Development Kit) from:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
After the installation of JDK, you need to add the bin directory of your java installation to the system path variable, so that the system could find the java compiler and interpreter, whenever needed.
We assume that you have downloaded and installed the latest version of JDK (Java Development Kit) from:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
After the installation of JDK, you need to add the bin directory of your java installation to the system path variable, so that the system could find the java compiler and interpreter, whenever needed.
·
When compiling a
program, you type the full file name, including the ".java" extension
and when running a program, you just type the name of the class whose main
function you want to execute.
·
Use javac command to
compile your java program files.
C:\ javac helloworld.java
Use java command to run or execute the compiler generated .class files.
C:\ java helloworld
Note that your directory structure may be different from the above.
C:\ javac helloworld.java
Use java command to run or execute the compiler generated .class files.
C:\ java helloworld
Note that your directory structure may be different from the above.
·
Java has two
"categories" of types: primitive types and reference
types.
Primitive Types
Primitive data types are generally used for local variables, parameters and instance variables (properties of an object). Primitive data types are located on the stack and we can only access their value, while objects are located on heap and we have a reference to those objects. Also, when invoking methods in java, primitive data types are always passed by value and objects are always passed by reference. All the primitive types have specified sizes that are machine independent for portability.
Primitive Types
Primitive data types are generally used for local variables, parameters and instance variables (properties of an object). Primitive data types are located on the stack and we can only access their value, while objects are located on heap and we have a reference to those objects. Also, when invoking methods in java, primitive data types are always passed by value and objects are always passed by reference. All the primitive types have specified sizes that are machine independent for portability.
boolean
|
same as bool in C++
1 byte in size |
char
|
holds one 16 bit unicode
character
2 bytes in size |
byte
|
8-bit signed integer
1 byte in size |
short
|
16-bit signed integer
2 bytes in size |
into
|
32-bit signed integer
4 bytes in size |
long
|
64-bit signed integer
8 bytes in size |
float
|
floating-point number
4 bytes in size |
double
|
double precision
floating-point number
8 bytes in size |
Reference Types
Arrays and objects of classes are the examples of Java reference types. Arrays and classes are discussed in the coming lessons. There are no struct, union, enum, unsigned, typedef, or pointer types in Java.
Java Arrays vs C++ Arrays |
Generally
speaking, there is not much difference between the Java and C or C++ arrays. As a C
/ C++ programmer you will find it very
easy to understand and work with arrays in Java.
In C++, when we declare an array, storage for the array is allocated. In Java, when we declare an array, we really only declare a pointer or reference to an array; storage for the array itself is not allocated until we use the "new" keyword. This difference is elaborated below:
C++
into A[10]; // A is an array of length 10
A[0] = 5; // set the 1st element of array A
JAVA
int [ ] A; // A is a reference / pointer to an array
A = new int [10]; // now A points to an array of length 10
A[0] = 5; // set the 1st element of the array pointed to by A
In both C++ and Java we can initialize an array using values in curly braces. Here's the example
Java code:
int [ ] myArray = {13, 12, 11}; // myArray points to an array of length 3
// containing the values 13, 12, and 11
In Java, a default initial value is assigned to each element of a newly allocated array if no initial value is specified. The default value depends on the type of the array element as shown below:
In C++, when we declare an array, storage for the array is allocated. In Java, when we declare an array, we really only declare a pointer or reference to an array; storage for the array itself is not allocated until we use the "new" keyword. This difference is elaborated below:
C++
into A[10]; // A is an array of length 10
A[0] = 5; // set the 1st element of array A
JAVA
int [ ] A; // A is a reference / pointer to an array
A = new int [10]; // now A points to an array of length 10
A[0] = 5; // set the 1st element of the array pointed to by A
In both C++ and Java we can initialize an array using values in curly braces. Here's the example
Java code:
int [ ] myArray = {13, 12, 11}; // myArray points to an array of length 3
// containing the values 13, 12, and 11
In Java, a default initial value is assigned to each element of a newly allocated array if no initial value is specified. The default value depends on the type of the array element as shown below:
Type
|
Value
|
boolean
|
false
|
char
|
'\u0000'
|
byte, int, short, long, float, double
|
0
|
any reference type e.g. a class object
|
null
|
In Java, array bounds are checked and an out-of-bounds array index always causes a runtime error.
Array Operations in Java |
Like C
and C++, array is a very
useful structure in Java programming
language too. There are several useful operations, provided by the Java
programming language that you can perform
on arrays. In this lesson we will show
you some of the very useful array operations in java
programming language.
Determining the length of an Array in Java:
We can determine the current length of an array (at runtime) using the ".length" operator:
int [ ] A = new int [10];
System.out.println (A.length); // this expression evaluates to 10
A = new int [15];
System.out.println (A.length); // now it evaluates to 15
Copying an Array:
In Java, we can copy an array using the array copy function. Like the output function printing, array copy is provided in java.lang.System, so you must use the name System.arraycopy. The function has five parameters:
src: the source array (the array from which to copy)
scopes: the starting position in the source array
dst: the destination array (the array into which to copy)
dstPos: the starting position in the destination array
count: how many values to copy
Here is an example:
int [ ] A, B;
A = new int[10];
.............// code to put values into A
B = new int[5];
System.arraycopy(A, 0, B, 0, 5) // copies first 5 values from A to B
System.arraycopy(A, 9, B, 4, 1) // copies last value from A into last
//element of B
Note that the destination array must already exist i.e. new must already have been used to allocate space for that array, and it must be large enough to hold all copied values, otherwise you will get a runtime error. Furthermore, the source array must have enough values to copy i.e. the length of the source array must be at least srcPos+count.
For arrays of primitive types, the types of the source and destination arrays must be the same. For arrays of non-primitive types, System.arraycopy(A, j, B, k, n) is OK if the assignment B[0] = A[0] would be OK. The array copy function also works when the source and destination arrays are the same array. For example, you can use it to "shift" the values in an array:
into [ ] A = {0, 1, 2, 3, 4};
System.arraycopy(A, 0, A, 1, 4);
After executing the above code, A has the values: [0, 0, 1, 2, 3].
Multidimensional Arrays:
As in C++, Java arrays can be multidimensional. For example, a 2-dimensional array is an array of arrays. However, a two-dimensional array need not be rectangular. Each row can be of a different length. Here's an example:
int [ ][ ] A; // A is a two-dimensional array
A = new int[5][]; // A now has 5 rows, but no columns yet
A[0] = new int [1]; // A's first row has 1 column
A[1] = new int [2]; // A's second row has 2 columns
A[2] = new int [3]; // A's third row has 3 columns
A[3] = new int [5]; // A's fourth row has 5 columns
A[4] = new int [5]; // A's fifth row also has 5 columns
Determining the length of an Array in Java:
We can determine the current length of an array (at runtime) using the ".length" operator:
int [ ] A = new int [10];
System.out.println (A.length); // this expression evaluates to 10
A = new int [15];
System.out.println (A.length); // now it evaluates to 15
Copying an Array:
In Java, we can copy an array using the array copy function. Like the output function printing, array copy is provided in java.lang.System, so you must use the name System.arraycopy. The function has five parameters:
src: the source array (the array from which to copy)
scopes: the starting position in the source array
dst: the destination array (the array into which to copy)
dstPos: the starting position in the destination array
count: how many values to copy
Here is an example:
int [ ] A, B;
A = new int[10];
.............// code to put values into A
B = new int[5];
System.arraycopy(A, 0, B, 0, 5) // copies first 5 values from A to B
System.arraycopy(A, 9, B, 4, 1) // copies last value from A into last
//element of B
Note that the destination array must already exist i.e. new must already have been used to allocate space for that array, and it must be large enough to hold all copied values, otherwise you will get a runtime error. Furthermore, the source array must have enough values to copy i.e. the length of the source array must be at least srcPos+count.
For arrays of primitive types, the types of the source and destination arrays must be the same. For arrays of non-primitive types, System.arraycopy(A, j, B, k, n) is OK if the assignment B[0] = A[0] would be OK. The array copy function also works when the source and destination arrays are the same array. For example, you can use it to "shift" the values in an array:
into [ ] A = {0, 1, 2, 3, 4};
System.arraycopy(A, 0, A, 1, 4);
After executing the above code, A has the values: [0, 0, 1, 2, 3].
Multidimensional Arrays:
As in C++, Java arrays can be multidimensional. For example, a 2-dimensional array is an array of arrays. However, a two-dimensional array need not be rectangular. Each row can be of a different length. Here's an example:
int [ ][ ] A; // A is a two-dimensional array
A = new int[5][]; // A now has 5 rows, but no columns yet
A[0] = new int [1]; // A's first row has 1 column
A[1] = new int [2]; // A's second row has 2 columns
A[2] = new int [3]; // A's third row has 3 columns
A[3] = new int [5]; // A's fourth row has 5 columns
A[4] = new int [5]; // A's fifth row also has 5 columns
Java Classes |
Classes and Objects are the heart and
sould of the OOP (Object Oriented Programming) and without them OOP cannot
exist. In this lesson we will start our discussion on Java
classes. As C++ programmers, you will glad to know that Java classesare
almost the same as C++ classes. Like C++ classes, Java classescontain
fields also called instance variables or properties of an object and methods. A
field is like a C++ data member, and a method is like a C++ member
function.
A Simple Example Class
In the following example, a List is defined to be an ordered collection of items of any type:
A Simple Example Class
In the following example, a List is defined to be an ordered collection of items of any type:
class List {
// fields
private Object [ ] items; // store the items in an array
private int numItems; // the current # of items in the list
//methods
// constructor function
public List() {
items = new Object[10];
numItems = 0;
}
// AddToEnd: add a given item to the end of the list
public void AddToEnd(Object ob){
}
}
In Java, all classes
(built-in or user-defined) are (implicitly) subclasses of the classObject.
Using an array of Object in the List class allows any kind of Object
(an instance of any class) to be stored in the list. However, primitive
types (int, char, etc) cannot be stored in the list as they are not
inherited from Object.
The Constructor Function |
As in C++,
constructor functions inJava are used to initialize the instances of a
class. They have no return type (not even void) and can be overloaded. You can
have multiple constructor functions, each with different numbers and
/ or types of arguments. If you don't write any constructor functions, a default
(no-argument) constructor (that doesn't do anything) will be supplied by the
compiler.
If you write a constructor that takes one or more arguments, no default constructor will be supplied and therefore, an attempt to create a new object without passing any arguments will cause a compile-time error.
It is often useful to have one constructor call another. For example, a constructor with no arguments might call a constructor with one argument, passing a default value. This call must be the first statement in the constructor. It is performed using this as if it were the name of the method. For example:
this( 10 );
The above is a call to a constructor that expects one integer argument.
Initialization of fields:
If you don't initialize a field i.e. either you don't write any constructor function, or your constructor function just doesn't assign a value to that field, the field will be given a default value, depending on its type. The default values of different types of variables have been discussed in a previous lesson.
If you write a constructor that takes one or more arguments, no default constructor will be supplied and therefore, an attempt to create a new object without passing any arguments will cause a compile-time error.
It is often useful to have one constructor call another. For example, a constructor with no arguments might call a constructor with one argument, passing a default value. This call must be the first statement in the constructor. It is performed using this as if it were the name of the method. For example:
this( 10 );
The above is a call to a constructor that expects one integer argument.
Initialization of fields:
If you don't initialize a field i.e. either you don't write any constructor function, or your constructor function just doesn't assign a value to that field, the field will be given a default value, depending on its type. The default values of different types of variables have been discussed in a previous lesson.
Java Access Specifiers |
Each field and method in a class
definition has an access level.Keywords private, protected andpublic are
used to declare a field and / or method as private, protected
and public, respectively. For package level access no modifies is
used i.e. if we use no access modifier / specifier, itdefaults to
package level access. The following table summarizes different access
specifiers / modifiers available in Java programming langauage:
private
|
accessible
only in this class
|
(
no modifier )
|
accessible
only in this package
|
protected
|
accessible
only in this package and in all subclasses of this class
|
public
|
accessible
everywhere this class is available
|
Similarly a class may be declared with the modifier public, in which case the class becomes visible to all classes, everywhere. On the contrary if a class has no modifier (the default, a.k.a. package-private) it becomes visible only within its own package.
For both fields and classes, package access is the default, and is used when no access modifier is specified. Java packages are discussed in the next lesson.
As discussed earlier, access control must be specified for every field and every method; there is no grouping as in C++. For example consider the following piece of code:
public
int x;
int y;
In the above piece of code only x is public; y gets the default, package access.
Static Fields and Methods
Fields and methods can also be declared static. If a field is declared as static, there is only one copy of the field for the entire class, rather than one copy for each instance of the class. A method that is declared as static cannot access any of the non-static fields of the class, and also it cannot call any non-static method. Methods that would be "free" functions in C++ i.e. not members of a class, should be static methods in Java. A public static field or method can be accessed from outside the class, with or without creating an instance of the class.
Final Fields and Methods
Fields and methods can also be declared final. A final method cannot be overridden in a subclass. A final field is like a constant: once it has been given a value, it cannot be assigned to again.
Java Packages |
Packages are
named groups of related classes. In java the classes can be grouped together in
packages. We can specify the package name using a package declaration:
package name ;
The package declaration must be the first (non-comment) line in the .java file. If a file contains a package declaration as above, the file must be in a subdirectory called name i.e. the directory name must match the package name.
We can access public classes in another (named) package using:
package-name.class-name
We can access the public fields and methods of such classes as under:
package-name.class-name.field-or-method-name
We can avoid having to include the package-name using import package-name.* orimport package-name.class-name at the beginning of the file after the package declaration, if any. The former imports all of the classes in the package, and the later imports just the named class. We can have as many import statements as we need. We must still use the class-name to access the classes in the package, and class-name.field-or-method-name to access the fields and methods of the class; the only thing you can leave off is the package name.
package name ;
The package declaration must be the first (non-comment) line in the .java file. If a file contains a package declaration as above, the file must be in a subdirectory called name i.e. the directory name must match the package name.
We can access public classes in another (named) package using:
package-name.class-name
We can access the public fields and methods of such classes as under:
package-name.class-name.field-or-method-name
We can avoid having to include the package-name using import package-name.* orimport package-name.class-name at the beginning of the file after the package declaration, if any. The former imports all of the classes in the package, and the later imports just the named class. We can have as many import statements as we need. We must still use the class-name to access the classes in the package, and class-name.field-or-method-name to access the fields and methods of the class; the only thing you can leave off is the package name.
Inheritance in Java |
From your C++
programming experience you must be aware of the fact that inheritance
plays a vital role in Object Oriented Programming. Being a pure object
oriented programming language Java also supports inheritance. However, Java
directly supports only single inheritance. In other words a sub-class can
inherit directly from a single super or parent class. Sub
classing from multiple base / super / parent classes is not allowed
in Java. This is totally in contrast to C++, where multiple inheritance
is allowed.
We use extends keyword to inherit from a super class as under:
public class subClass extends superClass { }
When a class is inherited:
We use extends keyword to inherit from a super class as under:
public class subClass extends superClass { }
When a class is inherited:
- All fields and methods are inherited.
- Public fields and methods of the parent /
super class are available to be used in the subclass.
- Private fields are also inherited, but cannot
be accessed by the methods of the subclass.
- Protected fields can be accessed by the
subclass methods.
When the final reserved word is specified on a
class specification, it means that class cannot be the parent of
any class i.e. a final class cannot be extended.
Each super-class method (except its constructors) can be inherited, overloaded, or overridden, as explained below:
Inherited: If no method with the same name is (re)defined in the subclass, then the subclass has that method with the same implementation as in the super class.
Overloaded: If the subclass defines a method with the same name, but with a different number of arguments or different argument types, then the subclass has two methods with that name: the old one defined by the super class, and the new one defined in the subclass.
Overridden: If the subclass defines a method with the same name, and the same number and types of arguments, then the subclass has only one method with that name: the new one defined in the subclass. A method CANNOT be overridden if it is defined as final in the super class.
Dynamic Binding
In C++, a method must be defined to be virtual to allow dynamic binding. In Java all method calls are dynamically bound unless the called method has been defined to befinal, in which case it cannot be overridden and all bindings are static.
Constructors
A subclass's constructors always call a super class constructor, either explicitly or implicitly. If there is no explicit call (and no call to another of the subclass constructors), then the no-argument version of the superclass constructor is called before executing any statements.
Each super-class method (except its constructors) can be inherited, overloaded, or overridden, as explained below:
Inherited: If no method with the same name is (re)defined in the subclass, then the subclass has that method with the same implementation as in the super class.
Overloaded: If the subclass defines a method with the same name, but with a different number of arguments or different argument types, then the subclass has two methods with that name: the old one defined by the super class, and the new one defined in the subclass.
Overridden: If the subclass defines a method with the same name, and the same number and types of arguments, then the subclass has only one method with that name: the new one defined in the subclass. A method CANNOT be overridden if it is defined as final in the super class.
Dynamic Binding
In C++, a method must be defined to be virtual to allow dynamic binding. In Java all method calls are dynamically bound unless the called method has been defined to befinal, in which case it cannot be overridden and all bindings are static.
Constructors
A subclass's constructors always call a super class constructor, either explicitly or implicitly. If there is no explicit call (and no call to another of the subclass constructors), then the no-argument version of the superclass constructor is called before executing any statements.
Abstract Classes and Methods |
In this
lesson we will learn about Abstract Classes and Abstract Methods in Java
programminglangauge.
Abstract Methods
An abstract method is a method that is declared in a (super)class, but not defined. In order to be instantiated, a subclass must provide the definition.
Abstract Classes
An abstract class is any class that includes an abstract method. It is similar to Pure virtual in C++. If a class includes an abstract method, the class must be declared abstract, too.
Code Example:
Abstract Methods
An abstract method is a method that is declared in a (super)class, but not defined. In order to be instantiated, a subclass must provide the definition.
Abstract Classes
An abstract class is any class that includes an abstract method. It is similar to Pure virtual in C++. If a class includes an abstract method, the class must be declared abstract, too.
Code Example:
abstract
class AbstractClass {
abstract public void Print();
// no body, just the function header
}
class
MyConcreteClass extends AbstractClass {
public void Print() {
// actual code goes here
}
}
Important
points to be remembered:
- An abstract class cannot be
instantiated.
- A subclass of an abstract class that
does not provide bodies for all abstract methods must also be declared
abstract.
- A subclass of a non-abstract class can override a
(non-abstract) method of its superclass, and declare it abstract. In that
case, the subclass must be declared abstract.
Java Interfaces |
As mentioned
earlier, multiple inheritances is directly not allowed in Java,
however, the same could be achieved through the concept of Interface in Java.
Inheritance implements the "is-a" relationship and an interface
is similar to a class, but can only contain public, static, final fields
(i.e., constants) and public abstract methods (i.e., just method headers,
with no bodies).
An interface is declared as shown below:
An interface is declared as shown below:
public
interface Employee {
void RaiseSalary( double d );
double GetSalary();
}
Note that both methods are
implicitly public and abstract (those keywords can be provided, but are not
necessary in an interface).
A class can implement one or more interfaces (in addition to extending one class). It must provide bodies for all of the methods declared in the interface, or else it must be abstract. For example:
A class can implement one or more interfaces (in addition to extending one class). It must provide bodies for all of the methods declared in the interface, or else it must be abstract. For example:
- public class TA implements Employee {
- void
RaiseSalary( double d ) {
- //
actual code here
- }
-
double GetSalary() {
- //
actual code here
- }
- }
- Public interfaces (like public classes) must
be in a file with the same name. A single class can implement
many interfaces at the same time thus achieving multiple
inheritance.
An interface can also be used as a "marker" with no fields or methods. A marker interface is used only to "mark" a class as having a property, and is testable via theinstanceof operator.
Type Conversion in Java
Java is much stronger than C++ in
the type conversions that are allowed.
In this lesson we will discussconversions among different primitive types i.e. char, byte, short, int, long, float, and double.
Booleans cannot be converted to other types. For the other primitive types (char, byte, short, int, long, float, and double), there are two kinds of conversion: implicit and explicit.
Implicit conversions:
An implicit conversion means that a value of one type is changed to a value of another type without any special directive from the programmer. A char can be implicitly converted to an int, a long, a float, or a double. For example, the following will compile without error:
char c = 'a';
int k = c;
long x = c;
float y = c;
double d = c;
For the other (numeric) primitive types, the basic rule is that implicit conversions can be done from one type to another if the range of values of the first type is a subset of the range of values of the second type. For example, a byte can be converted to a short, int, long or float; a short can be converted to an int, long, float, or double, etc.
Explicit conversions:
Explicit conversions are done via casting. The name of the type to which you want a value converted is given, in parentheses, in front of the value. For example, the following code casts a value of type double to a value of type int, and a value of type double to a value of type short:
double d = 5.6;
int k = (int)d;
short s = (short)(d * 2.0);
Casting can be used to convert among any of the primitive types except Boolean. Please note that casting can lose information; for example, floating-point values are truncated when they are cast to integers (e.g. the value of k in the code fragment given above is 5).
In this lesson we will discussconversions among different primitive types i.e. char, byte, short, int, long, float, and double.
Booleans cannot be converted to other types. For the other primitive types (char, byte, short, int, long, float, and double), there are two kinds of conversion: implicit and explicit.
Implicit conversions:
An implicit conversion means that a value of one type is changed to a value of another type without any special directive from the programmer. A char can be implicitly converted to an int, a long, a float, or a double. For example, the following will compile without error:
char c = 'a';
int k = c;
long x = c;
float y = c;
double d = c;
For the other (numeric) primitive types, the basic rule is that implicit conversions can be done from one type to another if the range of values of the first type is a subset of the range of values of the second type. For example, a byte can be converted to a short, int, long or float; a short can be converted to an int, long, float, or double, etc.
Explicit conversions:
Explicit conversions are done via casting. The name of the type to which you want a value converted is given, in parentheses, in front of the value. For example, the following code casts a value of type double to a value of type int, and a value of type double to a value of type short:
double d = 5.6;
int k = (int)d;
short s = (short)(d * 2.0);
Casting can be used to convert among any of the primitive types except Boolean. Please note that casting can lose information; for example, floating-point values are truncated when they are cast to integers (e.g. the value of k in the code fragment given above is 5).
Useful Java Classes
In this lesson we will learn
about some basic Java classes that are really useful . These useful
classes are provided in the java.langpackage.
The first one is the Object class. The Object class is the base class of all the java classes. All Java classes are implicitly derived from the Object class. The Object class provides a number of useful methods like toString() etc. As all classes in Java are implicitly derived from the Object class, all the methods defined in the Object class are automatically available in every Java class.
The second useful Java class is the String class. Like in C++ the String class in Java issued to manipulate text.
String Creation:
String S1 = "hello", // initialize from a string literal
S2 = new String("bye"), // use new and the String constructor
S3 = new String(S1); // use new and a different constructor
String concatenation
String S1 = “hello” + “world”;
String S2 = S1 + “!”;
String S3 = S1 + 10;
The java.lang.String class has many useful methods. If you are interested, just explore the Srtring class in the Java documentation.
Java SDK also provides classes for primitive types. These include: Boolean, Integer, Double, Float etc. Note that variables of type bool, int, double, float etc. are not objects whereas variable of type Boolean, Integer, Double, Float etc. are objects.
The first one is the Object class. The Object class is the base class of all the java classes. All Java classes are implicitly derived from the Object class. The Object class provides a number of useful methods like toString() etc. As all classes in Java are implicitly derived from the Object class, all the methods defined in the Object class are automatically available in every Java class.
The second useful Java class is the String class. Like in C++ the String class in Java issued to manipulate text.
String Creation:
String S1 = "hello", // initialize from a string literal
S2 = new String("bye"), // use new and the String constructor
S3 = new String(S1); // use new and a different constructor
String concatenation
String S1 = “hello” + “world”;
String S2 = S1 + “!”;
String S3 = S1 + 10;
The java.lang.String class has many useful methods. If you are interested, just explore the Srtring class in the Java documentation.
Java SDK also provides classes for primitive types. These include: Boolean, Integer, Double, Float etc. Note that variables of type bool, int, double, float etc. are not objects whereas variable of type Boolean, Integer, Double, Float etc. are objects.
Java Classes vs C++ Classes
In C++, when
we declare a variable whose type is a class, storage is
allocated for an object of that class, and the class's constructor
function is called to initialize that instance o f theclass. On the other hand,
in Javawhen we declare a variable whose type is a class, we
really declare apointer or reference to a class object;
no storage is allocated for the classobject, and no constructor function
is called unless we use the "new" keyword. This is elaborated with
the help of the following example:
Let us assume we have the following class:
class MyClass {
// class definition goes here
}
Let us first look at C++
MyClass m; // m is an object of type MyClass
// the constructor function is called to initialize M.
MyClass *pm; // pm is a pointer to an object of type MyClass
// no object exists yet, no constructor function has been called
pm = new MyClass; // now storage for an object of MyClass has been
// allocated and the constructor function has been called
Now the same thing in Java
MyClass m; // pm is a pointer to an object of type MyClass
// no object exists yet, no constructor function has been called
m = new MyClass(); // now storage for an object of MyClass has been
// allocated and the constructor function has been called. Note
// that you must use parentheses even when you are not
// passing any arguments to the constructor function
// Also note that there is a simple ‘.’ (dot) operator used to
// access members or send message. Java does not use -> operator.
Let us assume we have the following class:
class MyClass {
// class definition goes here
}
Let us first look at C++
MyClass m; // m is an object of type MyClass
// the constructor function is called to initialize M.
MyClass *pm; // pm is a pointer to an object of type MyClass
// no object exists yet, no constructor function has been called
pm = new MyClass; // now storage for an object of MyClass has been
// allocated and the constructor function has been called
Now the same thing in Java
MyClass m; // pm is a pointer to an object of type MyClass
// no object exists yet, no constructor function has been called
m = new MyClass(); // now storage for an object of MyClass has been
// allocated and the constructor function has been called. Note
// that you must use parentheses even when you are not
// passing any arguments to the constructor function
// Also note that there is a simple ‘.’ (dot) operator used to
// access members or send message. Java does not use -> operator.
Parameter Passing in Java
In Java, all
parameters are passed by value, but for arrays and objects of
classes only a reference to the actual parameter, which really is a pointer, is
passed. Therefore changing an array element or a class field inside the
function does change the actual parameter's element or field. Being a
programmer, this demands extra care from you. This would become clearer as
you go through the following code examples of parameter passing by
value and parameter passing by reference in Java:
PARAMETER PASSING BY REFERENCE:
PARAMETER PASSING BY REFERENCE:
void f( int [ ] A ) {
A[0] = 10; //
change an element of parameter A
}
void g() {
int [ ] B = new int [3];
B[0] = 5;
f(B);
//
B[0] is now 10, because function f changed the
//
first element of the array
}
PARAMETER PASSING BY VALUE:
void f( int
A ) {
A = 10; //
change the value of parameter A to 10
}
void g() {
int B =
5;
f(B);
//
B has not changed even though the function f changed the
//
value to 10
}
Exception Handling in Java 1
Exception handling in Java
is based on C++ but is designed to be more in line with OOP. It includes a
collection of predefined exceptions that are implicitly raised by the JVM. All
java exceptions are objects of classes that are descendents of Throw
able class. There are two predefined subclasses of Throw able: Error
and Exception.
Error and its descendents are related to errors thrown by JVM, e.g. out of heap memory. Such an exception is never thrown by the user programs and should not be handled by the user.
User programs can define their own exception classes. Convention in Java is that such class’s subclass the Exception class. There are two predefined descendents of Exception class: IOException and Runtime Exception. IOException deals with errors in I/O operations. In the case of RuntimeException there are some predefined exceptions which are, in many cases, thrown by JVM for errors such as out of boundsexception, and Null pointer exception.
Checked and Unchecked Exceptions
Exceptions of class Error and RuntimeException are called unchecked exceptions. They are never a concern of the compiler. A program can catch unchecked exceptions but it is not required. All others are checked exceptions. Compiler ensures that all the checked exceptions a method can throw are either listed in its throws clause or are handled inside the method.
Error and its descendents are related to errors thrown by JVM, e.g. out of heap memory. Such an exception is never thrown by the user programs and should not be handled by the user.
User programs can define their own exception classes. Convention in Java is that such class’s subclass the Exception class. There are two predefined descendents of Exception class: IOException and Runtime Exception. IOException deals with errors in I/O operations. In the case of RuntimeException there are some predefined exceptions which are, in many cases, thrown by JVM for errors such as out of boundsexception, and Null pointer exception.
Checked and Unchecked Exceptions
Exceptions of class Error and RuntimeException are called unchecked exceptions. They are never a concern of the compiler. A program can catch unchecked exceptions but it is not required. All others are checked exceptions. Compiler ensures that all the checked exceptions a method can throw are either listed in its throws clause or are handled inside the method.
We will
continue our discussion on Exception handling in this lesson. In this lesson we
will learn to codeException handlers.
Exception Handler
Exception handler in Java is similar to C++ except that the parameter of every catch must be present and its class must be descendent of Throwable. The syntax of try is exactly same as C++ except that there is an optional finally clause as well.
Consider the following example:
Exception Handler
Exception handler in Java is similar to C++ except that the parameter of every catch must be present and its class must be descendent of Throwable. The syntax of try is exactly same as C++ except that there is an optional finally clause as well.
Consider the following example:
class
MyException extends Exception {
public MyException() { }
public MyException(String message) {
super (message);
}
}
This exception can be thrown with
throw new MyException();
Or
MyException myExceptionObject = new MyException();
throw myExceptionObject;
Binding of exception is also similar to C++. If an exception is thrown in the compound statement of try construct, it is bound to the first handler (catch function) immediately following the try clause whose parameter is the same class as the thrown object or an ancestor of it. Exceptions can be handled and then re-thrown by including a throw statement without an operand at the end of the handler. To ensure that exceptions that can be thrown in a try clause are always handled in a method, a special handler can be written that matches all exceptions. For example:
catch (Exception anyException) {
}
throw new MyException();
Or
MyException myExceptionObject = new MyException();
throw myExceptionObject;
Binding of exception is also similar to C++. If an exception is thrown in the compound statement of try construct, it is bound to the first handler (catch function) immediately following the try clause whose parameter is the same class as the thrown object or an ancestor of it. Exceptions can be handled and then re-thrown by including a throw statement without an operand at the end of the handler. To ensure that exceptions that can be thrown in a try clause are always handled in a method, a special handler can be written that matches all exceptions. For example:
catch (Exception anyException) {
}
Exception Handling in Java 3
In this
lesson we will continue our discussion on exception handling inJava
programming langauge.
During program execution, the Java runtime system stores the class name of every object. getClass() can be used to get an object that stores the class name. It has a getName() method. The name of the class of the actual parameter of the throw statement can be retrieved in the handler as shown below.
anyException.getClass().getName();
In the case of a user defined exception, the thrown object could include any number of data fields that might be useful in the handler.
throws Clause
The throws clause is overloaded in C++ and conveys two different meanings: one asspecification and the other as command. Java is similar in syntax but different in semantics. The appearance of an exception class name in the throws clause of Java method specifies that the exception class or any of its descendents can be thrown by the method.
A C++ program unit that does not include a throws clause can throw any exceptions. A Java method that does not include a throws clause cannot throw any checked exception, it does not handle. A method cannot declare more exceptions in its throws clause than the methods it overrides, though it may declare fewer. A method that does not throw a particular exception, but calls another method that could throw the exception, must list the exception in its throws clause.
The finally clause
A Java exception handler may have a finally clause too. A finally clause always executes when its try block executes (whether or not there is an exception). The use of try, catch and finally is presented below:
During program execution, the Java runtime system stores the class name of every object. getClass() can be used to get an object that stores the class name. It has a getName() method. The name of the class of the actual parameter of the throw statement can be retrieved in the handler as shown below.
anyException.getClass().getName();
In the case of a user defined exception, the thrown object could include any number of data fields that might be useful in the handler.
throws Clause
The throws clause is overloaded in C++ and conveys two different meanings: one asspecification and the other as command. Java is similar in syntax but different in semantics. The appearance of an exception class name in the throws clause of Java method specifies that the exception class or any of its descendents can be thrown by the method.
A C++ program unit that does not include a throws clause can throw any exceptions. A Java method that does not include a throws clause cannot throw any checked exception, it does not handle. A method cannot declare more exceptions in its throws clause than the methods it overrides, though it may declare fewer. A method that does not throw a particular exception, but calls another method that could throw the exception, must list the exception in its throws clause.
The finally clause
A Java exception handler may have a finally clause too. A finally clause always executes when its try block executes (whether or not there is an exception). The use of try, catch and finally is presented below:
try {
}
catch () {
}
finally {
}
A finally clause is usually
included to make sure that some clean-up (e.g. closing opened files)
is done.
Exception Handling in Java 4
In this
lesson we will conclude our discussion on exception handling in Java programming language.
There is something more to understand about the finally clause in order to use it effectively. If the finally clause includes a transfer of control statement (return, break, continue, throw) then that statement overrides any transfer of control initiated in the try or in a catch clause.
First, let's assume that the finally clause does not include any transfer of control. Here are the situations that can arise:
There is something more to understand about the finally clause in order to use it effectively. If the finally clause includes a transfer of control statement (return, break, continue, throw) then that statement overrides any transfer of control initiated in the try or in a catch clause.
First, let's assume that the finally clause does not include any transfer of control. Here are the situations that can arise:
- No exception occurs during execution of the
try, and no transfer of control is executed in the try. In this
case the finally clause executes, then the statement following the try
block.
- No exception occurs during execution of the
try, but it does execute a transfer of control. In this case the
finally clause executes, and then the transfer of control takes
place.
- An exception does occur during
execution of the try, and there is no catch clause for that
exception. Now the finally clause executes, then the uncaught exception is
"passed up" to the next enclosing try block,
possibly in a calling function.
- An exception does occur during
execution of the try, and there is a catch clause for that exception. The
catch clause does not execute a transfer of control. In
this case the catch clause executes, then the finally clause,
then the statement following the try block.
- An exception does occur during
execution of the try, there is a catch clause for that exception, and the
catch clause does execute a transfer of control. Here, the
catch clause executes, then the finally clause, then the transfer of
control takes place.
If the finally block does include a transfer of control, then that takes precedence over any transfer of control executed in the try or in an executed catch clause. So for all of the cases listed above, the finally clause would execute, then its transfer of control would take place. Here's one example:
try {
return 0;
}
finally {
return 2;
}
The result of executing this code
is that 2 is returned. Note that this is rather confusing! The moral is that
you probably do not want to include transfer-of-control statements in both
the try statements and the finally clause, or in both a catch clause and the
finally clause.
Java Threads
Java
supports concurrency through threads which are lightweight processes. A thread
is similar to a real process in that a thread and a running
program are threads of execution. A thread takes advantage of the
resources allocated for that program instead of having to allocate those
resources again. A thread has its own stack and program counter. The
code running within the thread works only within the context implied by
the stack and PC, also called an execution context.
Creating Java Threads
There are two ways to create our own Thread object:
Creating Java Threads
There are two ways to create our own Thread object:
- Sub classing the Thread class and
instantiating a new object of that class
- Implementing the Runnable interface
In both
cases the run() method should be implemented. This is elaborated with
the help of following examples:
Example of Extending Thread
Example of Extending Thread
public class
Thread Example extends Thread {
public void run () {
for (int i = 1; i <= 100; i++) {
System.out.println(“Thread: ” + i);
}
}
}
Example of
Implementing Runnable
public class
Runnable Example implements Runnable {
public void run () {
for (int i = 1; i <= 100; i++) {
System.out.println (“Runnable: ” + i);
}
}
}
It may be
noted that both of these are very similar to each other with minor syntactic
and semantic differences.
Starting the Threads
A thread is started by simply sending the start message to the thread. This is shown in the following example:
Starting the Threads
A thread is started by simply sending the start message to the thread. This is shown in the following example:
public class
ThreadsStartExample {
public static void main (String argv[]) {
new ThreadExample ().start ();
new Thread(new RunnableExample ()).start
();
}
}
Java Threads 2
Thread
Methods
Some of the common thread methods are listed below:
Some of the common thread methods are listed below:
- start()
- sleep()
- yield()
- run()
- wait()
- notify()
- notifyAll()
- setPriority()
Thread Synchronization - Wait and Notify
Threads are based upon the concept of a Monitor. The wait() and notify() methods are used just like wait and signal in a Monitor. The following example of a producer-consumer problem elaborates the concept of thread synchronization and sharing objects between threads inside a single Java program:
class Buffer
{
private int [ ] buf;
private int head, tail, max, size;
public Buffer (int buf_size) {
buf = new int [buf_size];
head =0; tail = 0; size = 0;
max = buf_size;
}
public synchronized void deposit (int item)
{
try {
while (size ==max) wait();
buf [tail] = item;
tail = (tail + 1) % max;
size++;
notify();
}
catch
(interruptedException e) {
// exception handler
}
}
public synchronized int fetch() {
int item = 0;
try {
while (size == 0)
wait();
item = buf [head]
;
head = (head + 1)
% max;
size--;
notify();
}
catch (interruptedException e) {
// exception
handler
}
return item;
}
}
class
Producer extends Thread {
private Buffer buffer;
public Producer (Buffer buf) {
buffer = buf;
}
public void run () {
int item;
while (true) {
//
create a new item
buffer.deposit(item);
}
}
}
class
Consumer implements Runnable {
private Buffer buffer;
public Consumer (Buffer buf) {
buffer = buf;
}
public void run () {
int item;
while (true) {
item = buffer.fetch();
// consume item
}
}
}
We can now
instantiate these threads as shown below:
Buffer buffer = new Buffer(100);
Producer producer1 = new Producer(buffer);
Consumer comsumer = new Consumer(buffer);
Thread consumer1 = new Thread(consumer);
producer1.start(); consumer1.start();
In this case the buffer is a shared variable used by both producer and consumer.
notify() and notifyAll()
There is a slight difference between notify() and notifyAll(). As the name suggest, notify() wakes up a single thread which is waiting on the object's lock. If there is more than one thread waiting, the choice is arbitrary i.e. there is no way to specify which waiting thread should be re-awakened. On the other hand, notifyAll() wakes up ALL waiting threads; the scheduler decides which one will run.
Buffer buffer = new Buffer(100);
Producer producer1 = new Producer(buffer);
Consumer comsumer = new Consumer(buffer);
Thread consumer1 = new Thread(consumer);
producer1.start(); consumer1.start();
In this case the buffer is a shared variable used by both producer and consumer.
notify() and notifyAll()
There is a slight difference between notify() and notifyAll(). As the name suggest, notify() wakes up a single thread which is waiting on the object's lock. If there is more than one thread waiting, the choice is arbitrary i.e. there is no way to specify which waiting thread should be re-awakened. On the other hand, notifyAll() wakes up ALL waiting threads; the scheduler decides which one will run.