:

JAVA its history

The purpose of this page is to give an overview of Java programming with a reference to sites or books with more detail. Java is one of the most popular programming languages. Java derives its syntax from C and its object orientated features from C++.

C was invented by Dennis Ritchie on a DEC PDP-11 running the UNIX operating system. C was the result of a development process that started with an older language called BCPL, developed by Martin Richards. BCPL influenced a language called B, invented by Ken Thompson, which led to the development of C in the 1970s. For many years, the de facto standard for C was the one supplied with the UNIX operating system and described in The C Programming Language by Brian Kernighan and Dennis Ritchie (Prentice-Hall, 1978). C was formally standardized in December 1989, when the American National Standards Institute (ANSI) standard for C was adopted.

C was and is a very popular programming language, but the complexity of large scale programs needed another programming methodology: Object Oriented Programming. OOP is a programming methodology that helps organize complex programs through the use of inheritance, encapsulation, and polymorphism. C++ extended C with the OOP methodology.

Java was conceived by James Gosling, Patrick Naughton, Chris Warth, Ed Frank, and Mike Sheridan at Sun Microsystems, Inc. in 1991. It took 18 months to develop the first working version. This language was initially called “Oak,” but was renamed “Java” in 1995. Between the initial implementation of Oak in the fall of 1992 and the public announcement of Java in the spring of 1995, many more people contributed to the design and evolution of the language. Bill Joy, Arthur van Hoff, Jonathan Payne, Frank Yellin, and Tim Lindholm were key contributors to the maturing of the original prototype.

Java is architecture neutral
The driving force behing the invention of Java was to create a portable, platform-independent language, mainly for consumer electronic devices. However, with the emergence of the World Wide Web, Java was propelled to the forefront of computer language design, because the Web, too, demanded portable programs. The output of a Java compiler is not executable code. Rather, it is bytecode. Bytecode is a highly optimized set of instructions designed to be executed by the Java run-time system, which is called the Java Virtual Machine (JVM). In essence, the original JVM was designed as an interpreter for bytecode. The fact that a Java program is executed by the JVM helps solve the major problems associated with web-based programs: security and portability. Java introduced applets. These are programs which the internet server sends to the client and executes in the client's browser. Shortly after introducing applets, servlets were introduced. A servlet is a small program that executes on the server. Just as applets dynamically extend the functionality of a web browser, servlets dynamically extend the functionality of a web server. Servlets are used to create dynamically generated content that is then served to the client.Thus, with the advent of the servlet, Java spanned both sides of the client/server connection.

Java has high performance

Although Java was designed as an interpreted language, there is nothing about Java that prevents on-the-fly compilation of bytecode into native code in order to boost performance. For this reason, the HotSpot technology was introduced not long after Java’s initial release. HotSpot provides a Just-In-Time (JIT) compiler for bytecode. When a JIT compiler is part of the JVM, selected portions of bytecode are compiled into executable code in real time, on a piece-by-piece, demand basis. It is important to understand that it is not practical to compile an entire Java program into executable code all at once, because Java performs various run-time checks that can be done only at run time. Instead, a JIT compiler compiles code as it is needed, during execution. Furthermore, not all sequences of bytecode are compiled—only those that will benefit from compilation. The remaining code is simply interpreted. However, the just-in-time approach still yields a significant performance boost. Even when dynamic compilation is applied to bytecode, the portability and safety features still apply, because the JVM is still in charge of the execution environment.

Java is Object Oriented
The purpose of a programming language is to perform a serie of transformations on data. A program therefore consists always of both code and data. The introduction of OOP introduced three concpets which improved the quality and efficiency of programming.

Encapsulation
Encapsulation is the mechanism that binds together code and the data it manipulates, and keeps both safe from outside interference and misuse. One way to think about encapsulation is as a protective wrapper that prevents the code and data from being arbitrarily accessed by other code defined outside the wrapper. Access to the code and data inside the wrapper is tightly controlled through a well-defined interface. Encapsulation in Java is achieved by the construct of a class.

Inheritance
Inheritance is the process by which one object acquires the properties of another object. It avoids duplication of code.

Poylomorphism
Polymorphism (from Greek, meaning “many forms”) is a feature that allows one interface to be used for a general class of actions. More generally, the concept of polymorphism is often expressed by the phrase “one interface, multiple methods.” This means that it is possible to design a generic interface to a group of related activities. This helps reduce complexity by allowing the same interface to be used to specify a general class of action. It is the compiler’s job to select the specific action (that is, method) as it applies to each situation.

Java is robust
To better understand how Java is robust, consider two of the main reasons for program failure: memory management mistakes and mishandled exceptional conditions (that is, run-time errors). Memory management can be a difficult, tedious task in traditional programming environments. For example, in C/C++, the programmer must manually allocate and free all dynamic memory. This sometimes leads to problems, because programmers will either forget to free memory that has been previously allocated or, worse, try to free some memory that another part of their code is still using. Java virtually eliminates these problems by managing memory allocation and deallocation for you. (In fact, deallocation is completely automatic, because Java provides garbage collection for unused objects.) Exceptional conditions in traditional environments often arise in situations such as division by zero or “file not found,” and they must be managed with clumsy and hard-to-read constructs. Java helps in this area by providing object-oriented exception handling. In a well-written Java program, all run-time errors can—and should—be managed by your program.

Java is Multithreaded
Java was designed to meet the real-world requirement of creating interactive, networked programs. To accomplish this, Java supports multithreaded programming, which allows you to write programs that do many things simultaneously. The Java run-time system comes with an elegant yet sophisticated solution for multiprocess synchronization that enables you to construct smoothly running interactive systems. Java’s easy-to-use approach to multithreading allows you to think about the specific behavior of your program, not the multitasking subsystem.

Programming with a language requires knowledge of: the development enviroment, the syntax, the data types, operators, key libraries, code organization methods. We will shortly discuss each of these topics in a way that a novice java programmer can find his way around.

Java is Distributed
Java is designed for the distributed environment of the Internet because it handles TCP/IP protocols. In fact, accessing a resource using a URL is not much different from accessing a file. Java also supports Remote Method Invocation (RMI). This feature enables a program to invoke methods across a network.

Java is Dynamic
Java programs carry with them substantial amounts of run-time type information that is used to verify and resolve accesses to objects at run time. This makes it possible to dynamically link code in a safe and expedient manner. This is crucial to the robustness of the Java environment, in which small fragments of bytecode may be dynamically updated on a running system.

Evolution of Java
Java started with release of Java 1.0. As from version 1.2 Sun repackaged the Java product as J2SE 2 (Java 2 Platform Standard Edition, Version 2), and the developers kit as JDK 2. From version 1.6 Sun renamed the product as Java SE 6 and JDK 6. The latest release is Java SE 7, it is released after the acquisition of Sun by Oracle.

Started with Java

JDK


Get the latest version of the Java Developers Kit and install.

The figure below shows how the code of the JDK is organized. The bin directory contains the set of Java tools, such as the compiler (javac.exe) and JVM (java.exe), that you use to develop and run Java programs. The jre (Java Runtime Environment) directories contain the files needed to run Java programs but not the development tools such as the compiler. The jre would be distributed with a program intended for users who do not need the development tools. The include directory contains files for linking Java programs to C or C++ code, and a set of demonstration programs come in the demo directory.

IDE


Although one can use only a simple text editor to develop Java programs it is advised to use a Integrated Development Environment (IDE) such as Netbeans, Eclipse or a simple IDE like DrJava

Source files


Java is organized around the concept of a class, interface, enumeration, or annotation type. The definition of each type is stored in a single source text file and is called a compilation unit. A source file should contain only one public type. The name of the source text file must match the name of the type and ends with .java. By convention names of types begin with an uppercase letter. Be aware that Java is case-sensitive.

Packages


To avoid name conflicts in the name of types (i.e. two or more types with the same name) Java implements namespace management by defining packages. Related types are grouped into a package. Access protection is another benefit of using packages. Naming a package is a very important aspect of creating a package. By convention a package is name as the inverted domain name and the project name added to it, i.e. com.mycompany.myproject or mycompany.myproject

To declare a package the follwing line must be add to each class or interface belonging to the package.


/*
 * Class
 */
 
 package com.mycompany.myproject;
 
 import java.util.*;
 
 class MyClass {
 
 }

One of the requirements for a package is that the source file should be contained in a directory structure that resembles the name of the package. This is simply creating a set of directories with the names given in the package name. Normally one split the source files (.java) from the class files (.class) as in the figure below.

Compling the package is easy:

cd project
javac -d ./classes/ ./src/com/mycompany/myproject/*.java

Once you have created your package you may want to use it in your program or you may wish to use another programmer's package or the packages in the Java API. There are three ways of using the resources in a package; inline package member declarations, importing only the package member that you want and importing the entire package.


class Test1 {
   java.util.Vector vector;  // inline member declaration
   
   Test() {
      vector = new java.util.Vector();
   }
}
//importing a single package member
import java.util.Vector;
class Test2 {
   Vector vector;
   
   Test() {
      vector = new Vector();
   }
}
//importing an entire package
import java.util.*;

class Test {
   ...
}

Class Path - How classes are found


The full path to the classes directory, c:\project\classes, is called the classpath. Both the compiler and the JVM construct the path to your .class files by adding the package name to the user class path. So if the CLASSPATH=c:\project\classes, and the package com.mycompany.myproject, then hen the compiler and JVM look for .class files in c:\project\classes\com\mycompany\myproject.

A user class path is set with the CLASSPATH system variable. A class path may include several paths, separated by a semicolon (Windows) or colon (Unix). By default, the compiler and the JVM search the current directory and the JAR file containing the Java platform classes so that these directories are automatically in your class path.

The CLASSPATH can also be set in the command line as in:

 c:\> javac -classpath c:\project\classes
for compilation and
 c:\> java -cp c:\project\classes
for running the program.

The java launcher puts the user class path string in the java.class.path system property. The possible sources of this value are:


See here for more details on how the compiler and runtime find classes.

JAR files

A Java Archive File, commonly referred to as a Jar File is nothing more than a compressed archive file. The file has two important characteristics:

Typically, Jar files are used to distribute Java software, these Jar files contains the actual class files of the programs archived in them.

Some benefits of using Jar files are:

The basic command for creating a Jar file is:

jar cvf jar-filename   input-files

The c option indicates that you wish to create a jar, the v option means verbose output and the f option indicates that output should be sent to a file, jar-filename is the name of the resulting Jar file and input-files are the files you wish to include.

The command to view the contents of a jar file is as follows:

jar tf jar-filename

The t option is to print a table of contents and the f option indicates that your are reading from a file, the jar-filename is the filename of the jar you wish to use.

If we wish to extract a file from the Jar file, we use the following command:

jar xf jar-filename  archived-files

The x option indicates we wish to extract files, the f option indicates from a jar file, the jar-filename is the filename of the jar file to extract from and the archived-files are the files to extract.

The Jar file automatically adds a manifest file to the jar file, the file is always in a directory named META-INF and is named MANIFEST.MF; these are, like Java, case sensitive. This file contins information about the jar file and the files it contains.

An example of modifying the manifest file is package sealing, which means that all classes defined in a package must be archived in the same Jar file. To do this you need to add a Name and Sealed header to the manifest file, the name contains the package name and the sealed header indicates whether it is sealed or not.

Name: MyCompany/MyProject/MyPackage/
Sealed: true

You would add this information to a text file, suppose it is named seal.txt, you can add this information to the manifest using the m option.

jar cmf seal.txt myJar.jar MyCompany

Two other important manifest headers are the Main-Class and Class-Path, which are used to bundle software into a Jar file so that the software can be run from within the Jar file. This is known as an executable Jar file. Assume your program is name Main.java which compiles to Main.class, and that it requires a jar file named jutil.jar in the lib directory. You will then add the following to a text file named headers.txt:

Main-Class: Main
Class-Path: ./lib/jutil.jar
                

Make sure the headers.txt has a blank new line at the end of it. You can use the following command to create the Jar file.

jar cmf headers.txt project.jar Main.class

You will use the Java tool to run the program packaged inside the Jar file. Simply issue the command:

java -jar project.jar

The Language

Java programs are a collection of whitespace, identifiers, literals, comments, operators, separators, and keywords.

Whitespace
Java is a free-form language. At least one whitespace character is required between each token that was not already delineated by an operator or separator. In Java, whitespace is a space, tab, or newline.

Identifiers
Identifiers are used to name things, such as classes, variables, and methods. An identifier may be any descriptive sequence of uppercase and lowercase letters, numbers, or the underscore and dollar-sign characters. (The dollar-sign character is not intended for general use.) They must not begin with a number. Identifiers are case sensitive.

Literals
A constant value in Java is created by using a literal representation of an integer 8, a floating point 2.5, a character 'X' or a string "text".

Comments Multiline: /* */, Single line: //, Documentation: /** */

Separators

Keywords There are 50 keywords.


Data Types

Java Is a Strongly Typed Language. The Java compiler checks all expressions and parameters to ensure that the types are compatible. There are no automatic coercions or conversions of conflicting types as in some languages. Any type mismatches are errors that must be corrected before the compiler will finish compiling the class.

The primitive data types of Java can be grouped into:

The primitive types represent single values—not objects. The primitive types are defined to have an explicit range and mathematical behavior, i.e. platform independent.

Variables

The variable is the basic unit of storage in a Java program. A variable is defined by the combination of an identifier, a type, and an optional initializer. In addition, all variables have a scope, which defines their visibility, and a lifetime. The basic form of a variable declaration is shown here:

type identifier [ = value ][, identifier [= value ] …];

Java allows variables to be declared within any block. A block is begun with an opening curly brace and ended by a closing curly brace. A block defines a scope. Variables declared inside a scope are not visible (that is, accessible) to code that is defined outside that scope. Variables are created when their scope is entered, and destroyed when their scope is left. Thus, the lifetime of a variable is confined to its scope. Although blocks can be nested, you cannot declare a variable to have the same name as one in an outer scope. It is fairly common to assign a value of one type to a variable of another type. If the two types are compatible, then Java will perform the conversion automatically. In other cases an explicit cast is a possibility. A cast has the form (target-type) value. In addition to assignments, there is another place where certain type conversions may occur: in expressions. Java automatically promotes each type in an expression as follows: First, all byte, short, and char values are promoted to int. Then, if one operand is a long, the whole expression is promoted to long. If one operand is a float, the entire expression is promoted to float. If any of the operands are double, the result is double.

Arrays

An array is a group of like-typed variables that are referred to by a common name. Arrays of any type can be created and may have one or more dimensions. A specific element in an array is accessed by its index. Arrays offer a convenient means of grouping related information. The general form of a one-dimensional array declaration is

type var-name[ ];
type[] var-name;

To allocate memory to an array the new operator has to be used:

array-var = new type [size];

Here, type specifies the type of data being allocated, size specifies the number of elements in the array, and array-var is the array variable that is linked to the array. That is, to use new to allocate an array, you must specify the type and number of elements to allocate. The elements in the array allocated by new will automatically be initialized to zero (for numeric types), false (for boolean), or null (for reference types). All array indexes start at zero.

In Java, multidimensional arrays are actually arrays of arrays. To declare a multidimensional array variable, specify each additional index using another set of square brackets. A two dimensional array: left index represents rows and the right index the columns. When you allocate memory for a multidimensional array, you need only specify the memory for the first (leftmost) dimension. You can allocate the remaining dimensions separately.

Operators

Java operators can be divided into the following four groups: arithmetic, bitwise, relational, and logical.

Arithmetic operators


IThe operator ++/-- are special. In the prefix form, the operand is incremented or decremented before the value is obtained for use in the expression. In postfix form, the previous value is obtained for use in the expression, and then the operand is modified.

Bitwise operators All of the integer types (except char) are signed integers. This means that they can represent negative values as well as positive ones. Java uses an encoding known as two’s complement, which means that negative numbers are represented by inverting (changing 1’s to 0’s and vice versa) all of the bits in a value, then adding 1 to the result. The reason Java (and most other computer languages) uses two’s complement is easy to see when you consider the issue of zero crossing. Assuming a byte value, zero is represented by 00000000. In one’s complement, simply inverting all of the bits creates 11111111, which creates negative zero. The trouble is that negative zero is invalid in integer math. This problem is solved by using two’s complement to represent negative values. When using two’s complement, 1 is added to the complement, producing 100000000. This produces a 1 bit too far to the left to fit back into the byte value, resulting in the desired behavior, where -0 is the same as 0, and 11111111 is the encoding for -1. To avoid unpleasant surprises, just remember that the high-order bit determines the sign of an integer no matter how that high-order bit gets set.


Relational operators
If you are coming from a C/C++ background, please note the following. In C/C++, these types of statements are very common:

int done;
//…
if(!done)… // Valid in C/C++
if(done)…  // but not in Java.

In Java, these statements must be written like this:
if(done == 0)… // This is Java-style.
if(done != 0)…

Boolean operators
Java provides two interesting Boolean operators not found in many other computer languages. These are secondary versions of the Boolean AND and OR operators, and are commonly known as short-circuit logical operators. As you can see from the preceding table, the OR operator results in true when A is true, no matter what B is. Similarly, the AND operator results in false when A is false, no matter what B is. If you use the || and && forms, rather than the | and & forms of these operators, Java will not bother to evaluate the right-hand operand when the outcome of the expression can be determined by the left operand alone. It is standard practice to use the short-circuit forms of AND and OR in cases involving Boolean logic, leaving the single-character versions exclusively for bitwise operations.

Assigment operator
The assignment operator is the single equal sign, =. The assignment operator works in Java much as it does in any other computer language. It allows you to create a chain of assignments i.e. x=y=z=100;

The ? operator
Java includes a special ternary (three-way) operator that can replace certain types of if-then-else statements. This operator is the ?. It can seem somewhat confusing at first, but the ? can be used very effectively once mastered. The ? has this general form:

expression1 ? expression2 : expression3

Operator precedece
Operators in the same row in the table below are equal in precedence. In binary operations, the order of evaluation is left to right (except for assignment, which evaluates right to left). Although they are technically separators, the [ ], ( ), and . can also act like operators. In that capacity, they would have the highest precedence. Parentheses raise the precedence of the operations that are inside them.

Control Statements

A programming language uses control statements to cause the flow of execution to advance and branch based on changes to the state of a program. Java’s program control statements can be put into the following categories: selection, iteration, and jump.

Selection statements
Java supports two selection statements: if and switch. Here is the general form of the if statement:

if (condition) statement1;
else statement2;
or in case of multiple lines a code block must be introduced:
if (condition) {
	statement1;
	statement2;
}
else statement2;

A common programming construct that is based upon a sequence of nested ifs is the if-else-if ladder. It looks like this:
if(condition)
  statement;
else if(condition)
  statement;
else if(condition)
  statement;
.
.
.
else
  statement;

The switch statement is Java’s multiway branch statement. It provides an easy way to dispatch execution to different parts of your code based on the value of an expression. As such, it often provides a better alternative than a large series of if-else-if statements. Here is the general form of a switch statement:


For versions of Java prior to JDK 7, expression must be of type byte, short, int, char, or an enumeration. Beginning with JDK 7, expression can also be of type String. Each value specified in the case statements must be a unique constant expression (such as a literal value). Duplicate case values are not allowed. The type of each value must be compatible with the type of expression. The break statement is used inside the switch to terminate a statement sequence. When a break statement is encountered, execution branches to the first line of code that follows the entire switch statement. This has the effect of “jumping out” of the switch. A switch statement is usually more efficient than a set of nested ifs. The Java compiler will inspect each of the case constants and create a “jump table” that it will use for selecting the path of execution depending on the value of the expression.

Iteration statements Java’s iteration statements are for, while, and do-while. The while loop is Java’s most fundamental loop statement. It repeats a statement or block while its controlling expression is true. Here is its general form:

while(condition) {
     // body of loop
}

The body of the while (or any other of Java’s loops) can be empty.

Sometimes it is desirable to execute the body of a loop at least once, even if the conditional expression is false to begin with. In other words, there are times when you would like to test the termination expression at the end of the loop rather than at the beginning. Fortunately, Java supplies a loop that does just that: the do-while. The do-while loop always executes its body at least once, because its conditional expression is at the bottom of the loop. Its general form is

do {
  // body of loop
} while (condition);

Here is the general form of the traditional for statement:

for(initialization; condition; iteration) {
   // body
}
Often the variable that controls a for loop is needed only for the purposes of the loop and is not used elsewhere. When this is the case, it is possible to declare the variable inside the initialization portion of the for. To allow two or more variables to control a for loop, Java permits you to include multiple statements in both the initialization and iteration portions of the for. Each statement is separated from the next by a comma.

The for-each style of for is also referred to as the enhanced for loop. The general form of the for-each version of the for is shown here:

for(type itr-var: collection) statement-block

The following fragment uses a traditional for loop to compute the sum of the values in an array:

int nums[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = 0;
for(int i=0; < 10; i++) sum += nums[i];

Jump statements
Java supports three jump statements: break, continue, and return. These statements transfer control to another part of your program. The break statement has three uses. First, as you have seen, it terminates a statement sequence in a switch statement. Second, it can be used to exit a loop. Third, it can be used as a “civilized” form of goto. The general form of the labeled break statement is shown here:

break label;

To name a block, put a label at the start of it. A label is any valid Java identifier followed by a colon. Once you have labeled a block, you can then use this label as the target of a break statement. Doing so causes execution to resume at the end of the labeled block. One of the most common uses for a labeled break statement is to exit from nested loops. Keep in mind that you cannot break to any label which is not defined for an enclosing block.

Sometimes it is useful to force an early iteration of a loop. That is, you might want to continue running the loop but stop processing the remainder of the code in its body for this particular iteration. This is, in effect, a goto just past the body of the loop, to the loop’s end. As with the break statement, continue may specify a label to describe which enclosing loop to continue.

The last control statement is return. The return statement is used to explicitly return from a method. That is, it causes program control to transfer back to the caller of the method. As such, it is categorized as a jump statement.

Classes

The class is at the core of Java. It is the logical construct upon which the entire Java language is built because it defines the shape and nature of an object. As such, the class forms the basis for object-oriented programming in Java. Any concept you wish to implement in a Java program must be encapsulated within a class. A class is a user defined data type, it is a template for an object, and an object is an instance of a class. The data, or variables, defined within a class are called instance variables. The code is contained within methods. The data, or variables, defined within a class are called instance variables. The code is contained within methods. The class declaration and the implementation of the methods are stored in the same place and not defined separately. This sometimes makes for very large .java files, since any class must be entirely defined in a single source file.

Creating objects
Obtaining objects of a class is a two-step process. First, you must declare a variable of the class type. This variable does not define an object. Instead, it is simply a variable that can refer to an object. Second, you must acquire an actual, physical copy of the object and assign it to that variable. You can do this using the new operator. The new operator dynamically allocates (that is, allocates at run time) memory for an object and returns a reference to it. This reference is, more or less, the address in memory of the object allocated by new. This reference is then stored in the variable. Thus, in Java, all class objects must be dynamically allocated.

Assignment of object
When you assign one object reference variable to another object reference variable, you are not creating a copy of the object, you are only making a copy of the reference. When an instance variable is accessed by code that is not part of the class in which that instance variable is defined, it must be done through an object, by use of the dot operator. However, when an instance variable is accessed by code that is part of the same class as the instance variable, that variable can be referred to directly. The same thing applies to methods.

Constructors
Java allows objects to initialize themselves when they are created. This automatic initialization is performed through the use of a constructor. A constructor initializes an object immediately upon creation. It has the same name as the class in which it resides and is syntactically similar to a method. Once defined, the constructor is automatically called immediately after the object is created, before the new operator completes. Constructors look a little strange because they have no return type, not even void. This is because the implicit return type of a class’ constructor is the class type itself.

This keyword
Sometimes a method will need to refer to the object that invoked it. To allow this, Java defines the this keyword. this can be used inside any method to refer to the current object. When a local variable has the same name as an instance variable, the local variable hides the instance variable. Because this lets you refer directly to the object, you can use it to resolve any namespace collisions that might occur between instance variables and local variables.

Garbage collection
When no references to an object exist, that object is assumed to be no longer needed, and the memory occupied by the object can be reclaimed. There is no explicit need to destroy objects as in C++. Garbage collection only occurs sporadically (if at all) during the execution of your program. It will not occur simply because one or more objects exist that are no longer used. Furthermore, different Java run-time implementations will take varying approaches to garbage collection, but for the most part, you should not have to think about it while writing your programs.

Finalize method
Sometimes an object will need to perform some action when it is destroyed. For example, if an object is holding some non-Java resource such as a file handle or character font, then you might want to make sure these resources are freed before an object is destroyed. To handle such situations, Java provides a mechanism called finalization. By using finalization, you can define specific actions that will occur when an object is just about to be reclaimed by the garbage collector. It is important to understand that finalize( ) is only called just prior to garbage collection. It is not called when an object goes out-of-scope, for example. This means that you cannot know when—or even if—finalize( ) will be executed. Therefore, your program should provide other means of releasing system resources, etc., used by the object. It must not rely on finalize( ) for normal program operation. If you are familiar with C++, then you know that C++ allows you to define a destructor for a class, which is called when an object goes out-of-scope. Java does not support this idea or provide for destructors. The finalize( ) method only approximates the function of a destructor. As you get more experienced with Java, you will see that the need for destructor functions is minimal because of Java’s garbage collection subsystem.

Overloading
In Java it is possible to define two or more methods within the same class that share the same name, as long as their parameter declarations are different. In addition to overloading normal methods, you can also overload constructor methods. In fact, for most real-world classes that you create, overloaded constructors will be the norm, not the exception.

Argument passing
In general, there are two ways that a computer language can pass an argument to a subroutine. The first way is call-by-value. This approach copies the value of an argument into the formal parameter of the subroutine. Therefore, changes made to the parameter of the subroutine have no effect on the argument. The second way an argument can be passed is call-by-reference. In this approach, a reference to an argument (not the value of the argument) is passed to the parameter. Inside the subroutine, this reference is used to access the actual argument specified in the call. This means that changes made to the parameter will affect the argument used to call the subroutine. As you will see, although Java uses call-by-value to pass all arguments, the precise effect differs between whether a primitive type or a reference type is passed. When an object reference is passed to a method, the reference itself is passed by use of call-by-value. However, since the value being passed refers to an object, the copy of that value will still refer to the same object that its corresponding argument does.

Returning objects
A method can return any type of data, including class types that you create. Since all objects are dynamically allocated using new, you don’t need to worry about an object going out-of-scope because the method in which it was created terminates. The object will continue to exist as long as there is a reference to it somewhere in your program. When there are no references to it, the object will be reclaimed the next time garbage collection takes place.

Recursion
Java supports recursion. Recursion is the process of defining something in terms of itself. As it relates to Java programming, recursion is the attribute that allows a method to call itself. A method that calls itself is said to be recursive. Recursive versions of many routines may execute a bit more slowly than the iterative equivalent because of the added overhead of the additional function calls. Many recursive calls to a method could cause a stack overrun. Because storage for parameters and local variables is on the stack and each new call creates a new copy of these variables, it is possible that the stack could be exhausted.

Access Control
How a member can be accessed is determined by the access modifier attached to its declaration. An access modifier precedes the rest of a member’s type specification. Java supplies a rich set of access modifiers. Java’s access modifiers are public, private, and protected. Java also defines a default access level. When a member of a class is modified by public, then that member can be accessed by any other code. When a member of a class is specified as private, then that member can only be accessed by other members of its class. When no access modifier is used, then by default the member of a class is public within its own package, but cannot be accessed outside of its package.

Static
There will be times when you will want to define a class member that will be used independently of any object of that class. Normally, a class member must be accessed only in conjunction with an object of its class. However, it is possible to create a member that can be used by itself, without reference to a specific instance. To create such a member, precede its declaration with the keyword static. When a member is declared static, it can be accessed before any objects of its class are created, and without reference to any object. You can declare both methods and variables to be static. Instance variables declared as static are, essentially, global variables. When objects of its class are declared, no copy of a static variable is made. Instead, all instances of the class share the same static variable. Methods declared as static have several restrictions:

If you need to do computation in order to initialize your static variables, you can declare a static block that gets executed exactly once, when the class is first loaded.

Final
A field can be declared as final. Doing so prevents its contents from being modified, making it, essentially, a constant. This means that you must initialize a final field when it is declared. You can do this in one of two ways: First, you can give it a value when it is declared. Second, you can assign it a value within a constructor.In addition to fields, both method parameters and local variables can be declared final. Declaring a parameter final prevents it from being changed within the method. Declaring a local variable final prevents it from being assigned a value more than once.

Nested Class
It is possible to define a class within another class; such classes are known as nested classes. The scope of a nested class is bounded by the scope of its enclosing class. Thus, if class B is defined within class A, then B does not exist independently of A. A nested class has access to the members, including private members, of the class in which it is nested. However, the enclosing class does not have access to the members of the nested class. A nested class that is declared directly within its enclosing class scope is a member of its enclosing class. It is also possible to declare a nested class that is local to a block. The most important type of nested class is the inner class. An inner class is a non-static nested class. It has access to all of the variables and methods of its outer class and may refer to them directly in the same way that other non-static members of the outer class do. It is important to realize that an instance of Inner can be created only within the scope of class Outer. The Java compiler generates an error message if any code outside of class Outer attempts to instantiate class Inner. In general, an inner class instance must be created by an enclosing scope.

String class
String is probably the most commonly used class in Java’s class library. The obvious reason for this is that strings are a very important part of programming. Objects of type String are immutable; once a String object is created, its contents cannot be altered. However you can always create a new one that contains the modifications or use StringBuffer, which allows strings to be altered, so all of the normal string manipulations are still available in Java.

Variable length arguments
Beginning with JDK 5, Java has included a feature that simplifies the creation of methods that need to take a variable number of arguments. This feature is called varargs and it is short for variable-length arguments. A method that takes a variable number of arguments is called a variable-arity method, or simply a varargs method. A variable-length argument is specified by three periods (…). For example, here is how vaTest( ) is written using a vararg: static void vaTest(int … v) { This syntax tells the compiler that vaTest( ) can be called with zero or more arguments. As a result, v is implicitly declared as an array of type int[ ]. A method can have “normal” parameters along with a variable-length parameter. However, the variable-length parameter must be the last parameter declared by the method.

Inheritance
Inheritance is one of the cornerstones of object-oriented programming because it allows the creation of hierarchical classifications. To inherit a class, you simply incorporate the definition of one class into another by using the extends keyword.


// create superclass
class A {
int i,j;
}
// create subclass
class B extends A {
int k;
}
The subclass B includes all of the members of its superclass, A. Java does not support the inheritance of multiple superclasses into a single subclass.

A class member that has been declared as private will remain private to its class. It is not accessible by any code outside its class, including subclasses.

A reference variable of a superclass can be assigned a reference to any subclass derived from that superclass. It is important to understand that it is the type of the reference variable—not the type of the object that it refers to—that determines what members can be accessed. That is, when a reference to a subclass object is assigned to a superclass reference variable, you will have access only to those parts of the object defined by the superclass.

In a class hierarchy, when a method in a subclass has the same name and type signature as a method in its superclass, then the method in the subclass is said to override the method in the superclass. When an overridden method is called from within its subclass, it will always refer to the version of that method defined by the subclass. To disallow a method from being overridden, specify final as a modifier at the start of its declaration. Methods declared as final can sometimes provide a performance enhancement. Declaring a class as final implicitly declares all of its methods as final.

Dynamic method dispatch is the mechanism by which a call to an overridden method is resolved at run time, rather than compile time. This is called late binding. When an overridden method is called through a superclass reference, Java determines which version of that method to execute based upon the type of the object being referred to at the time the call occurs. Thus, this determination is made at run time. When different types of objects are referred to, different versions of an overridden method will be called. In other words, it is the type of the object being referred to (not the type of the reference variable) that determines which version of an overridden method will be executed. Overridden methods in Java are similar to virtual functions in other languages like C++.

You can require that certain methods be overridden by subclasses by specifying the abstract type modifier. Any class that contains one or more abstract methods must also be declared abstract. To declare a class abstract, you simply use the abstract keyword in front of the class keyword at the beginning of the class declaration. There can be no objects of an abstract class. Also, you cannot declare abstract constructors, or abstract static methods. Any subclass of an abstract class must either implement all of the abstract methods in the superclass, or be declared abstract itself. Although abstract classes cannot be used to instantiate objects, they can be used to create object references, because Java’s approach to run-time polymorphism is implemented through the use of superclass references. Thus, it must be possible to create a reference to an abstract class so that it can be used to point to a subclass object.

Java allows a hierarchy of inheritance in which a subclass becomes a superclass of another subclass. However, no class can be a superclass of itself. Whenever a subclass needs to refer to its immediate superclass, it can do so by use of the keyword super. Super has two general forms. The first, super(), calls the superclass’ constructor. The second, super.member, is used to access a member of the superclass that has been hidden by a member of a subclass with the same name. super( ) always refers to the constructor in the closest superclass. Constructors are called in order of derivation, from superclass to subclass. Further, since super( ) must be the first statement executed in a subclass’ constructor, this order is the same whether or not super( ) is used. If super( ) is not used, then the default or parameterless constructor of each superclass will be executed.

Object Class
There is one special class, Object, defined by Java. All other classes are subclasses of Object. That is, Object is a superclass of all other classes. Object has following methods defined.

The methods getClass( ), notify( ), notifyAll( ), and wait( ) are declared as final. You may override the others. The equals( ) method compares two objects. It returns true if the objects are equal, and false otherwise. The precise definition of equality can vary, depending on the type of objects being compared. The toString( ) method returns a string that contains a description of the object on which it is called. Also, this method is automatically called when an object is output using println( ). Many classes override this method. Doing so allows them to tailor a description specifically for the types of objects that they create.

Access Modifiers
Classes and packages are both means of encapsulating and containing the name space and scope of variables and methods. Packages act as containers for classes and other subordinate packages. Classes act as containers for data and code. The class is Java’s smallest unit of abstraction. Because of the interplay between classes and packages, Java addresses four categories of visibility for class members:

The three access modifiers, private, public, and protected, provide a variety of ways to produce the many levels of access to class members. See how the access to class members interact:
When a class is declared as public, it is accessible by any other code. If a class has default access, then it can only be accessed by other code within its same package. When a class is public, it must be the only public class declared in the file, and the file must have the same name as the class.

Interfaces

Using the keyword interface, you can fully abstract a class’ interface from its implementation. That is, using interface, you can specify what a class must do, but not how it does it. Interfaces are syntactically similar to classes, but they lack instance variables, and their methods are declared without any body. Any number of classes can implement an interface. Also, one class can implement any number of interfaces. To implement an interface, a class must create the complete set of methods defined by the interface. However, each class is free to determine the details of its own implementation. By providing the interface keyword, Java allows you to fully utilize the “one interface, multiple methods” aspect of polymorphism.

When no access modifier is included, then default access results, and the interface is only available to other members of the package in which it is declared. When it is declared as public, the interface can be used by any other code. In this case, the interface must be the only public interface declared in the file, and the file must have the same name as the interface. The methods that are declared have no bodies. They end with a semicolon after the parameter list. They are, essentially, abstract methods; there can be no default implementation of any method specified within an interface. Each class that includes an interface must implement all of the methods. Variables can be declared inside of interface declarations. They are implicitly final and static, meaning they cannot be changed by the implementing class. They must also be initialized. All methods and variables are implicitly public. To implement an interface, include the implements clause in a class definition, and then create the methods defined by the interface. The methods that implement an interface must be declared public. The type signature of the implementing method must match exactly the type signature specified in the interface definition. You can declare variables as object references that use an interface rather than a class type. Any instance of any class that implements the declared interface can be referred to by such a variable. When you call a method through one of these references, the correct version will be called based on the actual instance of the interface being referred to. This is one of the key features of interfaces. If a class includes an interface but does not fully implement the methods defined by that interface, then that class must be declared as abstract. An interface can be declared a member of a class or another interface. Such an interface is called a member interface or a nested interface. A nested interface can be declared as public, private, or protected. This differs from a top-level interface, which must either be declared as public or use the default access level, as previously described. When a nested interface is used outside of its enclosing scope, it must be qualified by the name of the class or interface of which it is a member. You can use interfaces to import shared constants into multiple classes by simply declaring an interface that contains variables that are initialized to the desired values. One interface can inherit another by use of the keyword extends. The syntax is the same as for inheriting classes. When a class implements an interface that inherits another interface, it must provide implementations for all methods defined within the interface inheritance chain.

Exceptional Handling

An exception is an abnormal condition that arises in a code sequence at run time. In other words, an exception is a runtime error. A Java exception is an object that describes an exceptional (that is, error) condition that has occurred in a piece of code. When an exceptional condition arises, an object representing that exception is created and thrown in the method that caused the error. That method may choose to handle the exception itself, or pass it on. Either way, at some point, the exception is caught and processed. Exceptions can be generated by the Java run-time system, or they can be manually generated by your code. Exceptions thrown by Java relate to fundamental errors that violate the rules of the Java language or the constraints of the Java execution environment. Manually generated exceptions are typically used to report some error condition to the caller of a method. Java exception handling is managed via five keywords: try, catch, throw, throws, and finally. Any exception that is not caught by your program will ultimately be processed by the default handler. The default handler displays a string describing the exception, prints a stack trace from the point at which the exception occurred, and terminates the program.

Exception types
All exception types are subclasses of the built-in class Throwable. Thus, Throwable is at the top of the exception class hierarchy. Immediately below Throwable are two subclasses that partition exceptions into two distinct branches. One branch is headed by Exception. This class is used for exceptional conditions that user programs should catch. This is also the class that you will subclass to create your own custom exception types. There is an important subclass of Exception, called RuntimeException. Exceptions of this type are automatically defined for the programs that you write and include things such as division by zero and invalid array indexing. The other branch is topped by Error, which defines exceptions that are not expected to be caught under normal circumstances by your program. Exceptions of type Error are used by the Java run-time system to indicate errors having to do with the run-time environment, itself.

Catch
You can specify two or more catch clauses, each catching a different type of exception. When an exception is thrown, each catch statement is inspected in order, and the first one whose type matches that of the exception is executed. After one catch statement executes, the others are bypassed, and execution continues after the try / catch block. When you use multiple catch statements, it is important to remember that exception subclasses must come before any of their superclasses. This is because a catch statement that uses a superclass will catch exceptions of that type plus any of its subclasses. As a consequence exceptions of type Exception will catch all exceptions and must be put the last in the sequence of specific catch statements. The try statement can be nested. That is, a try statement can be inside the block of another try. Each time a try statement is entered, the context of that exception is pushed on the stack. If an inner try statement does not have a catch handler for a particular exception, the stack is unwound and the next try statement’s catch handlers are inspected for a match. This continues until one of the catch statements succeeds, or until all of the nested try statements are exhausted. If no catch statement matches, then the Java run-time system will handle the exception. Nesting of try statements can occur in less obvious ways when method calls are involved. For example, you can enclose a call to a method within a try block. Inside that method is another try statement. In this case, the try within the method is still nested inside the outer try block, which calls the method.

Throw
it is possible for your program to throw an exception explicitly, using the throw statement. The general form of throw is shown here: throw ThrowableInstance; ThrowableInstance must be an object of type Throwable or a subclass of Throwable. The flow of execution stops immediately after the throw statement; any subsequent statements are not executed. The nearest enclosing try block is inspected to see if it has a catch statement that matches the type of exception. If it does find a match, control is transferred to that statement. If not, then the next enclosing try statement is inspected, and so on. If no matching catch is found, then the default exception handler halts the program and prints the stack trace. There are two ways you can obtain a Throwable object: using a parameter in a catch clause or creating one with the new operator.


// Demonstrate throw.
class ThrowDemo {
  static void demoproc() {
    try {
      throw new NullPointerException("demo");
    } catch(NullPointerException e) {
      System.out.println("Caught inside demoproc.");
      throw e; // rethrow the exception
    }
  }

  public static void main(String args[]) {
    try {
      demoproc();
    } catch(NullPointerException e) {
      System.out.println("Recaught: " + e);
    }
  }
}

Throws
If a method is capable of causing an exception that it does not handle, it must specify this behavior so that callers of the method can guard themselves against that exception. You do this by including a throws clause in the method’s declaration. A throws clause lists the types of exceptions that a method might throw. This is necessary for all exceptions, except those of type Error or RuntimeException, or any of their subclasses. All other exceptions that a method can throw must be declared in the throws clause. If they are not, a compile-time error will result.

Finally When exceptions are thrown, execution in a method takes a rather abrupt, nonlinear path that alters the normal flow through the method. Depending upon how the method is coded, it is even possible for an exception to cause the method to return prematurely. This could be a problem in some methods. For example, if a method opens a file upon entry and closes it upon exit, then you will not want the code that closes the file to be bypassed by the exception-handling mechanism. The finally keyword is designed to address this contingency. finally creates a block of code that will be executed after a try /catch block has completed and before the code following the try/catch block. The finally block will execute whether or not an exception is thrown. If an exception is thrown, the finally block will execute even if no catch statement matches the exception. Any time a method is about to return to the caller from inside a try/catch block, via an uncaught exception or an explicit return statement, the finally clause is also executed just before the method returns. This can be useful for closing file handles and freeing up any other resources that might have been allocated at the beginning of a method with the intent of disposing of them before returning. The finally clause is optional. However, each try statement requires at least one catch or a finally clause.

Java's build in exceptions
Inside the standard package java.lang, Java defines several exception classes. A few have been used by the preceding examples. The most general of these exceptions are subclasses of the standard type RuntimeException. As previously explained, these exceptions need not be included in any method’s throws list. In the language of Java, these are called unchecked exceptions because the compiler does not check to see if a method handles or throws these exceptions. The unchecked exceptions defined in java.lang are listed in Table 10-1. Table 10-2 lists those exceptions defined by java.lang that must be included in a method’s throws list if that method can generate one of these exceptions and does not handle it itself. These are called checked exceptions. Java defines several other types of exceptions that relate to its various class libraries.

Unchecked exceptions
Checked exceptions

Creating program specific exception classes
Define a subclass of Exception (which is, of course, a subclass of Throwable). Your subclasses don’t need to actually implement anything—it is their existence in the type system that allows you to use them as exceptions. All exceptions have the methods defined by Throwable available to them. Exception defines four constructors. Exception( ) creates an exception that has no description. Exception(String msg) specifies a description of the exception. Although specifying a description when an exception is created is often useful, sometimes it is better to override toString( ). Throwable(Throwable causeExc) causeExc is the exception that causes the current exception. Throwable(String msg, Throwable causeExc) specifies a description at the same time that you specify a cause exception.

Methods of Throwable

JDK 7 new features
The multi-catch feature allows two or more exceptions to be caught by the same catch clause. It is not uncommon for two or more exception handlers to use the same code sequence even though they respond to different exceptions. Instead of having to catch each exception type individually, now you can use a single catch clause to handle all of the exceptions without code duplication. To use a multi-catch, separate each exception type in the catch clause with the OR operator. Each multi-catch parameter is implicitly final. (You can explicitly specify final, if desired, but it is not necessary.) Because each multi-catch parameter is implicitly final, it can’t be assigned a new value.

The more precise rethrow feature restricts the type of exceptions that can be rethrown to only those checked exceptions that the associated try block throws, that are not handled by a preceding catch clause, and that are a subtype or supertype of the parameter. For the more precise rethrow feature to be in force, the catch parameter must be either effectively final, which means that it must not be assigned a new value inside the catch block, or explicitly declared final.

Multithreading

Unlike some computer languages, Java provides built-in support for multithreaded programming. A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution. Thus, multithreading is a specialized form of multitasking.

there are two distinct types of multitasking: process-based and thread-based. It is important to understand the difference between the two. For many readers, process-based multitasking is the more familiar form. A process is, in essence, a program that is executing. Thus, process-based multitasking is the feature that allows your computer to run two or more programs concurrently. For example, process-based multitasking enables you to run the Java compiler at the same time that you are using a text editor or visiting a web site. In process-based multitasking, a program is the smallest unit of code that can be dispatched by the scheduler. In a thread-based multitasking environment, the thread is the smallest unit of dispatchable code. This means that a single program can perform two or more tasks simultaneously. For instance, a text editor can format text at the same time that it is printing, as long as these two actions are being performed by two separate threads. Thus, process-based multitasking deals with the “big picture,” and thread-based multitasking handles the details. Multitasking threads require less overhead than multitasking processes. Processes are heavyweight tasks that require their own separate address spaces. Interprocess communication is expensive and limited. Context switching from one process to another is also costly. Threads, on the other hand, are lighter weight. They share the same address space and cooperatively share the same heavyweight process. Interthread communication is inexpensive, and context switching from one thread to the next is lower in cost. While Java programs make use of process-based multitasking environments, process-based multitasking is not under Java’s control. However, multithreaded multitasking is.

The Java Thread Model
The Java run-time system depends on threads for many things, and all the class libraries are designed with multithreading in mind. In fact, Java uses threads to enable the entire environment to be asynchronous. This helps reduce inefficiency by preventing the waste of CPU cycles. The value of a multithreaded environment is best understood in contrast to its counterpart. Single-threaded systems use an approach called an event loop with polling. In this model, a single thread of control runs in an infinite loop, polling a single event queue to decide what to do next. Once this polling mechanism returns with, say, a signal that a network file is ready to be read, then the event loop dispatches control to the appropriate event handler. Until this event handler returns, nothing else can happen in the program. This wastes CPU time. The benefit of Java’s multithreading is that the main loop/polling mechanism is eliminated. One thread can pause without stopping other parts of your program. For example, the idle time created when a thread reads data from a network or waits for user input can be utilized elsewhere. Multithreading allows animation loops to sleep for a second between each frame without causing the whole system to pause. When a thread blocks in a Java program, only the single thread that is blocked pauses. All other threads continue to run. over the past few years, multi-core systems have become commonplace. Of course, single-core systems are still in widespread use. It is important to understand that Java’s multithreading features work in both types of systems. In a single-core system, concurrently executing threads share the CPU, with each thread receiving a slice of CPU time. Therefore, in a single-core system, two or more threads do not actually run at the same time, but idle CPU time is utilized. However, in multi-core systems, it is possible for two or more threads to actually execute simultaneously. In many cases, this can further improve program efficiency and increase the speed of certain operations. JDK 7 adds the Fork/Join Framework, which provides a powerful means of creating multithreaded applications that automatically scale to make best use of multi-core environments. The Fork/Join Framework is part of Java’s support for parallel programming, which is the name commonly given to the techniques that optimize some types of algorithms for parallel execution in systems that have more than one CPU.

Thread status
Threads exist in several states. Here is a general description. A thread can be running. It can be ready to run as soon as it gets CPU time. A running thread can be suspended, which temporarily halts its activity. A suspended thread can then be resumed, allowing it to pick up where it left off. A thread can be blocked when waiting for a resource. At any time, a thread can be terminated, which halts its execution immediately. Once terminated, a thread cannot be resumed.

Thread priorities
Thread Priorities Java assigns to each thread a priority that determines how that thread should be treated with respect to the others. Thread priorities are integers that specify the relative priority of one thread to another. As an absolute value, a priority is meaningless; a higher-priority thread doesn’t run any faster than a lower-priority thread if it is the only thread running. Instead, a thread’s priority is used to decide when to switch from one running thread to the next. This is called a context switch. The rules that determine when a context switch takes place are simple:
1)A thread can voluntarily relinquish control. This is done by explicitly yielding, sleeping, or blocking on pending I/O. In this scenario, all other threads are examined, and the highest-priority thread that is ready to run is given the CPU.
2)A thread can be preempted by a higher-priority thread. In this case, a lower-priority thread that does not yield the processor is simply preempted—no matter what it is doing—by a higher-priority thread. Basically, as soon as a higher-priority thread wants to run, it does. This is called preemptive multitasking. In cases where two threads with the same priority are competing for CPU cycles, the situation is a bit complicated. For operating systems such as Windows, threads of equal priority are time-sliced automatically in round-robin fashion. For other types of operating systems, threads of equal priority must voluntarily yield control to their peers. If they don’t, the other threads will not run. To set a thread’s priority, use the setPriority( ) method, which is a member of Thread. This is its general form:

final void setPriority(int level)
Here, level specifies the new priority setting for the calling thread. The value of level must be within the range MIN_PRIORITY and MAX_PRIORITY. Currently, these values are 1 and 10, respectively. To return a thread to default priority, specify NORM_PRIORITY, which is currently 5. These priorities are defined as static final variables within Thread. You can obtain the current priority setting by calling the getPriority( ) method of Thread, shown here:
final int getPriority( )

Messaging
After you divide your program into separate threads, you need to define how they will communicate with each other. When programming with some other languages, you must depend on the operating system to establish communication between threads. This, of course, adds overhead. By contrast, Java provides a clean, low-cost way for two or more threads to talk to each other, via calls to predefined methods that all objects have. Java’s messaging system allows a thread to enter a synchronized method on an object, and then wait there until some other thread explicitly notifies it to come out.

Java Thread class and Runnable Interface
Java’s multithreading system is built upon the Thread class, its methods, and its companion interface, Runnable. Thread encapsulates a thread of execution. Since you can’t directly refer to the ethereal state of a running thread, you will deal with it through its proxy, the Thread instance that spawned it. To create a new thread, your program will either extend Thread or implement the Runnable interface. The Thread class defines several methods that help manage threads.

The main Thread
When a Java program starts up, one thread begins running immediately. This is usually called the main thread of your program, because it is the one that is executed when your program begins. Although the main thread is created automatically when your program is started, it can be controlled through a Thread object. To do so, you must obtain a reference to it by calling the method currentThread( ), which is a public static member of Thread. Its general form is shown here:
static Thread currentThread( )

Creating a thread
In the most general sense, you create a thread by instantiating an object of type Thread. ava defines two ways in which this can be accomplished:

The easiest way to create a thread is to create a class that implements the Runnable interface. To implement Runnable, a class need only implement a single method called run( ). In a multithreaded program, the main thread must be the last thread to finish running. this can be done via the method:
final void join( ) throws InterruptedException
This method waits until the thread on which it is called terminates. Its name comes from the concept of the calling thread waiting until the specified thread joins it. Additional forms of join( ) allow you to specify a maximum amount of time that you want to wait for the specified thread to terminate. An alternative way is using the method isAlive().

class A implements Runnable {
	Thread t;
	A() {
		t=new Thread(this,"A");
		t.start();
	}
	public void run() {
		try {
		 // do something
		 }
		 catch(InterruptedException e) {
			system.out.println("Interrupted");
		 }
	}
}
// run A
class Main {
	public static void main(String args[]) {
		A  a= new A(); // create a new thread
		try {
			// do something else, but wait for child thread to finish
			a.t.join();
		}
		catch(Exception e) {
			system.out.println("Exception"+e);
		}
	}
}
The second way to create a thread is to create a new class that extends Thread, and then to create an instance of that class.

class A extends Thread {
	Thread t;
	A() {
		super("A");
		start();
	}
	public void run() {
		try {
		 // do something
		 }
		 catch(InterruptedException e) {
			system.out.println("Interrupted");
		 }
	}
}

Synchronization
When two or more threads need access to a shared resource, they need some way to ensure that the resource will be used by only one thread at a time. The process by which this is achieved is called synchronization. As you will see, Java provides unique, language-level support for it. Key to synchronization is the concept of the monitor. A monitor is an object that is used as a mutually exclusive lock. Only one thread can own a monitor at a given time. When a thread acquires a lock, it is said to have entered the monitor. All other threads attempting to enter the locked monitor will be suspended until the first thread exits the monitor. These other threads are said to be waiting for the monitor. A thread that owns a monitor can reenter the same monitor if it so desires. To enter an object’s monitor, just call a method that has been modified with the synchronized keyword. While a thread is inside a synchronized method, all other threads that try to call it (or any other synchronized method) on the same instance have to wait. To exit the monitor and relinquish control of the object to the next waiting thread, the owner of the monitor simply returns from the synchronized method. Alternatively a synchronization block can be used:

synchronized(object) {
   // statements to be synchronized
}

Interthread communication
Java includes an elegant interprocess communication mechanism via the wait( ), notify( ), and notifyAll( ) methods. These methods are implemented as final methods in Object, so all classes have them. All three methods can be called only from within a synchronized context. Although conceptually advanced from a computer science perspective, the rules for using these methods are actually quite simple:

lthough wait( ) normally waits until notify( ) or notifyAll( ) is called, there is a possibility that in very rare cases the waiting thread could be awakened due to a spurious wakeup. Calls to wait( ) should take place within a loop that checks the condition on which the thread is waiting. In the example below we have following classes: Q:queue, P:producer, C:consumer

class Q {
	int n;
	boolean valueSet=false;
	
	synchronized int get() {
		while(!valueSet) 
			try {
				wait();
			}
			catch(InterruptedException e) {
				system.out.println("InterruptedException caught");
			}
		valueSet=false;
		notify();
		return n;
		}
}
synchronized void put(int n) {
	while(valueSet) 
			try {
				wait();
			}
			catch(InterruptedException e) {
				system.out.println("InterruptedException caught");
			}
		this.n=n;.
		valueSet=true;
		notify();
	}
}
class P implements Runnable {
	Q q;
	
	P(Q q) {
		this.q=q;
		new Thread(this,"P").start();
	}
	public void run() {
		int i=0;
		
		while(true) {
			q.put(i++);
		}
	}
}
class Q implements Runnable {
	Q q;
	P(Q q) {
		this.q=q;
		new Thread(this,"P").start();
	}
	public void run() {
		int i=0;
		
		while(true) {
			q.get();
		}
	}
}

Deadlock
A special type of error that you need to avoid that relates specifically to multitasking is deadlock, which occurs when two threads have a circular dependency on a pair of synchronized objects.

Suspend and resume
the suspend(), resume() and stop() methods of the Object class should not be used for suspending, resuming or stopping a thread. These methods have been deprecated as from SDK 2. Instead a thread must be designed so that the run( ) method periodically checks to determine whether that thread should suspend, resume, or stop its own execution. Typically, this is accomplished by establishing a flag variable that indicates the execution state of the thread. As long as this flag is set to “running,” the run( ) method must continue to let the thread execute. If this variable is set to “suspend,” the thread must pause. If it is set to “stop,” the thread must terminate.


class A implements Runnable {
	Thread t;
	boolean suspendFlag;
	A() {
		t=new Thread(this,"A");.
		suspendFlag=false;
		t.start();
	}
	public void run() {
		try {
			 // do something in a loop
			....
			 synchronized(this) {
				while(suspendFlag) {
					wait();
				}
			 }
		 }
		 catch(InterruptedException e) {
			system.out.println("Interrupted");
		 }
	}
	synschronized void mysuspend() {
		suspendFlag=true;
	}
	synchronized void myresume() {
		suspendFlag=false;
		notify();
	}
}

Thread state
As mentioned earlier in this chapter, a thread can exist in a number of different states. You can obtain the current state of a thread by calling the getState( ) method defined by Thread. It is shown here:

Thread.State getState( )

References



Copyright ©2012 Jacq Krol. All rights reserved. Created September 2012; last updated September 2012.