Recitation: Friday 10/13/00, 11-12:00 (1-390):
TA: Petros Komodromos,
1-245,
petros@mit.edu
The portability of Java programs is based on the Java Virtual Machine (Java VM) and the intermediate compilation into bytecode. The bytecode can, then, be interpreted by the Java VM, which translates the bytecode instructions into machine instructions that your computer can understand and execute.
The Java platform consists essentially by the Java VM, which takes care of the compilation and interpretation issues (e.g. portability), and by the Java API, which provides a large collection of software components that can be directly used by a Java programmer. You can read more about it in the on-line paper "The Java Platform", by Douglas Kramer.
The Application Programming Interface (API) provides several classes that can be used to efficiently write programs with graphics content and graphical user interfaces. The latter can be achieved with C++ only by combining it with graphic libraries such as Open Inventor or OpenGL, and with toolkit libraries such as TCL and TK.
In addition, Java facilitates the development of programs that deal with networking, security issues, databases, 3D graphics, and many other issues that a typical high level language, such as C++, does not provide.
The following are good references to learn Java:
Java is a pure Object Oriented Programming
(OOP) language. Any Java program is built from classes. C++ can be
used as an OOP language but not necessarily since someone can use it to
develop non-object oriented programs.
The simplest, probably, Java program is a Java application which prints a message. A Java application is a Java program that can be executed independently without the need of any browser.
The following java program is written in a file named welcome.java":
welcome.java
class Welcome
{
public static void main(String args[])
{
System.out.println("Welcome to 1.124");
}
}
Because global functions are not allowable in
Java we need to provide the main() function in a class. In
addition, we need to make it public so as to be accessible, and
static
so as to be a class function rather than being a function associated with
a certain instance of the class. The main function must have a single
parameter of type String[]
and must return nothing (i.e. being void). Any class can have its
own main function.
To compile a java program the java compiler javac is used as follows:
Many other programming languages, such as C/C++, are using a compiler, which translates the source code files into machine instructions. Although the execution of compiled programs is much faster, the executable cannot run on a machine with a different architecture, since it recognizes a different set of instructions.
Java combines both a compiler and an interpreter. The compiler (javac) compiles the Java source code files into bytecode, and the interpreter (java) is used every time the program is executed to translate the bytecode (i.e. the Virtual Machine instructions) to the specific machine instructions and execute them. This way Java programs can run on any type of computer and under any operating system assuming that the Java interpreter is available and can be used on that machine. However, Java programs are, in general, slower than compiled programs (e.g. C++ executable programs) since interpretation takes place before execution.
Java Development Kit (JDK) also provides an appletviewer to check and run applets, a debugger named jdb to debug Java programs, and several other tools that help in the development and documentation of Java programs.
Java applications are stand alone Java programs that can be executed without the need of a browser, while the Java applets run within a Java compatible browser. The execution of any Java application begins with the main method of the corresponding class, i.e.. the class with which the Java interpreter was invoked. The above example is a Java application, while the following is a simple Java applet.
A Java applet is based on a set of conventions and functionalities that are inherited that allows it to be executed in an appletviewer or any Java enabled browser. The source code for the applet is provided below, followed by the html file that needs to be used so as to load the class from a Java enabled browser, or using the appletviewer provided with the Java Development Kit (JDK).
An applet inherits (extending) the Applet class provided by the java.applet package of the Java Core API. Here, the AWT Applet is used, mostly for historical reasons. Today, the Swing JApplet is preffered in most cases. In the following example the function paint(), which is inherited, is overridden by the new definition. This function is used to draw the applet in the browser, or the appletviewer.
myApplet.java:
import java.applet.Applet;The above program is compiled using the javac compiler, i.e. executing the command:
import java.awt.Graphics;public class myApplet extends Applet
{
public void paint(Graphics g)
{
g.drawString("Welcome to 1.124", 50, 35);
}
}
javac myapplet.javaThe resulting file with the bytecode is the myApplet.class which takes its name from the name of the class. This file can be loaded and interpreted in any Java enabled browser, or the appletviewer, using an html file.
The html code is used to specify at least the location and the dimensions of the applet to be loaded.
myApplet.html:
<HTML><HEAD>
<TITLE> A simple program to run a Java Applet</TITLE>
</HEAD><BODY>
Here is the class myApplet is loaded:
<APPLET CODE="myApplet.class" WIDTH=150 HEIGHT=100 align=center>
</APPLET>
</BODY></HTML>
It is possible to write a Java program that can work
both as an applet and as an application.
You can, also, find detailed instructions on how to write your first Java program at the Lesson: "Your First Cup of Java" of the on line Java Tutorial, which is provided by SUN.
The following are the primitive (or built-in) data types:
byte < short < int < long < float < doubleA char can be promoted to an int, long, float or double. However, a boolean cannot be converted to any other primitive data type, since boolean values are not considered to be numbers. The following table presents all the allowable promotions:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
An assignment from a "higher" order to a "lower" is allowed only when an explicit casting is used, because information may be lost from the conversion, e.g.: int x = (int) 4.75;
Each of the primitive data types has a corresponding class, called wrapper class, defined in the java.lang package. e.g. a double primitive data type has the corresponding class Double.
The scope of a variable is where the variable is accessible. It is specified by the location where the variable is defined. There are 4 different scope categories:
The scope of a function or an exception-handler parameter is the entire corresponding function.
A named constant can be defined using the keywords static and final. Static indicates that it is a class variable, while final indicates that its value cannot be changed after it has been initialized.
e.g.: static final double PI = 3.1414926
The following precedence table (copied from the Java Tutorial) lists the operators according to their precedence order. Higher precedence operators are evaluated before lower precedence operators.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For operators on the same line, that have equal precedence, associativity decides which operator to be executed first. In Java all operators, except the assignment operators, have left associativity.
A block of statements, i.e. statements within curly braces, may appear instead of a single statement.
The following are the control structures of Java:
if(logical
test)
statement;
else
if(logical test)
statement;
else
statement;
switch(variable)
{
case value1:
statements
break;
case value3:
statements
break;
case value4: case value5:
statements
break;
default:
statements
}
while(logical
test)
statement;
do
{
statements;
} while(logical test);
Java provides the break and continue as branching statements. The former cause the exit from the block of statements in which it resides, while the latter causes the flow of control to be transfer to the next iteration. There are also labeled versions of break and continue in which labels are used where the control is transferred to the block with the specified label. The labeled break and the labeled continue are useful in nested loops. A return statement also is used to return form a function, passing control to the invoking function.
In addition, Java supports the documentation comment which is enclosed between /** and */. Comments of this kind are used for automatically generated documentation using the javadoc tool of the Java Development Kid (JDK).
Having wrote a java file, such as the file Welcome1.java
below, using javadoc someone can automatically create an html file corresponding
to that java source code.
Welcome1.java:
/**Then, the javadoc can be used to create the corresponding html file:
* This class can take a variable number of parameters on the command
* line. Program execution begins with the main() method.
*/
public class Welcome1
{
/**
* The main entry point for the application.
*
* @param args Array of parameters passed to the
* application via the command line.
*/
public static void main (String[] args)
{
System.out.println("Welcome to 1.124!!!!");
}
}
>javadoc Welcome1.jaThe html file Welcome1.html, which you can visit here, is the main html file generated by javadoc using the above procedure.
Loading source file Welcome1.java...
Constructing Javadoc information...
Building tree for all the packages and classes...
Building index for all the packages and classes...
Generating overview-tree.html...
Generating index-all.html...
Generating deprecated-list.html...
Building index for all classes...
Generating allclasses-frame.html...
Generating index.html...
Generating packages.html...
Generating Welcome1.html...
Generating serialized-form.html...
Generating package-list...
Generating help-doc.html...
Generating stylesheet.css...
The declaration of an array in Java does not make any memory allocation, but simply defines a reference to an array. A new statement is required to make the proper allocation of memory. Then, an element of the array is accessed using an index within square brackets. An array in Java has a length field which stores the number of its elements.
The class System has a function called arraycopy() that can be used to copy part or the whole array to another array.
A function in which an array is passed as an argument can change it, since the reference to that array is what is passed by value. An array can be returned from a function, i.e. the return data type of a function can be an array.
The length of an array is fixed upon its definition and cannot be modified. A class named Vector can be used to represent an array whose size can be modified.
An array can contain references to other arrays or objects, in which case memory for the individual members of the array must also be explicitly allocated using a new statement.
A multidimensional array can be defined using an array whose elements are arrays. If the array has the same number of columns then such an array is defined using a statement similar to the following: double x[][] = new double [n][m]. Otherwise for each row a new expression is used to dynamically allocate memory for it.
Example of arrays:
class introArrays
{
public static final int SIZE=5;public static void main(String args[])
{
double d[] = new double[SIZE];
int [] i ;
i = new int[SIZE];for(int j=0 ; j<d.length ; j++)
d[j] = j/2;
for(int j=0 ; j<i.length ; j++)
i[j] = j*j;for(int j=0 ; j<SIZE ; j++)
System.out.println( " d[" + j + "] = " + d[j]);
for(int j=0 ; j<i.length ; j++)
System.out.println( " i[" + j + "] = " + i[j]);int m=5, n=3;
int im, in;
double x[][] = new double[m][n];for(im=0;im<m;im++)
{
System.out.println();
for(in=0;in<n;in++)
{
System.out.print(" " + x[im][in] + " ");
}
}}
}
Output:
d[0] = 0.0In Java you can easily have a ragged array, such as a 2-D array with rows of different lengths. When an array is created only the length of the primary array must be specified. The length of the sub-arrays can be left unspecified until they are created, as it is shown in the following example.
d[1] = 0.0
d[2] = 1.0
d[3] = 1.0
d[4] = 2.0
i[0] = 0
i[1] = 1
i[2] = 4
i[3] = 9
i[4] = 160.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
Example of a ragged array:
class TriangularArray
{
public static void main(String args[])
{
int i, j;double [][]x;
x = new double[5][];
for(i=0;i<5;i++)
{
x[i] = new double[i+1];System.out.println();
for(j=0;j<i+1;j++)
{
x[i][j] = (i+1)*10+j+1;
System.out.print(" " + x[i][j] + " ");
}
}
}
}
Output:
11.0
21.0 22.0
31.0 32.0 33.0
41.0 42.0 43.0 44.0
51.0 52.0 53.0 54.0 55.0
An object is an instance of a class. It is created using a new operator which instantiates the class, allocating memory for a new object, and initializes the objects data members, usually through constructors rather than directly. The new operator returns a reference to the new instance of the class that has been created, i.e. to the new object. The new object is referenced typically by the variable at the left side of the new statement. The declaration of an object, e.g. Point p, does not allocate any memory for an instance of the class Point. It simply declares that p can be used as a reference to an instance of the class Point. In Java memory for objects is allocated from the heap using the keyword new. If there is not enough memory to be allocated the garbage collector may run to reclaim some memory and if there is still not enough memory an OutOfMemoryError exception is thrown. The variable that is associated with an object, in contrast to a variable of primitive data type, is actually a reference to that object.
A class member data, or static field, is a field that is shared among all objects of that class, as in C++. Similarly, static (or class) functions are methods, that can operate on class member data (static fields), or perform operations on the entire class and not on a certain instance of the class (i.e. object). A static function can access only static members, variables or functions, of the class, since it is not invoked on a specific object. Static fields and methods are declared using the keyword static at its declaration. Class variables and methods are accessible from the class itself. There is no need to create an object, i.e. to instantiate the class in order to access its class (i.e. static) members. The static variables of a class are initialized before any use of any static variable and before the use of any of the member functions of the class.
When a class is defined it is required to use the keyword class followed by the name of the class in the class declaration. The class body, in curly braces, follows the class declaration. Other possible components of a class declaration are the public, abstract, final, extends (superclass), and implements (one or more interfaces). If any, or all, of these optional components are not provided the Java compiler considers the defaults, which are nonpublic, non-abstract, non-final subclass of the class Object that does not implement any interface.
A public class is publicly accessible, i.e. it can be used by classes in any package, not necessarily classes in its package.
An abstract class is a class that cannot be instantiated, i.e. no objects of that class can be defined. An abstract class must necessarily be subclassed to be used, since it may contain methods with no implementation, i.e. abstract methods. an abstract class may provide definitions of all or some of the methods that the subclasses may inherit. Although an abstract class cannot be instantiated, a reference to an abstract class can be defined and used to achieve polymorphism. Typically, some of the functions are left to be implemented by the subclasses. If a class contains an abstract function then the class is abstract and cannot be instantiated. In that case the class should be explicitly specified as abstract.
A final class is a class that cannot be subclassed. Specifying a class as final automatically implies that all its methods are considered to be final. Specifying a class, or a function, as final may sometimes be useful, considering security and optimization issues.
The extends <superclass>
specifies that the class that is declared is a subclass of the provided
<superclass>.
Finally, the implements<interface1>,
<interface2>,...., specifies that the class implements one or more
interfaces, whose names are provided after the keyword
implements
in a comma separated list.
Note that assigning a reference data type variable, i.e. a variable that refers to an instance of a class, to another reference variable then both variables refer to the same object. The function clone() may be used to actually make an actual complete copy of one object to another, i.e. copy the object state into a new identical object but in a different memory location.
The following is an example of a simple class. The class has two member data, x and y, and a class (or static) data and has no functions.
Example of a simple class:
class Point
{
public double x, y=100; // data member (or field)
public static int num = 0; // class or static data member
}class introClasses
{
public static void main(String args[])
{
Point p1; // declaration of a Point object
Point p2 = new Point();
Point.num++;p1 = new Point();
p1.y = 1.1;
p1.x = 2.2;
p2.num ++;
System.out.println("Number = " + Point.num);
System.out.print("\n p1: x = " + p1.x + " y = " + p1.y );
System.out.println("\n p2: x = " + p2.x + " y = " + p2.y );
}
}
Output:
Number = 2
p1: x = 2.2 y = 1.1
p2: x = 0.0 y = 100.0
Another constructor of a class can be invoked from inside a constructor of that class using this which is a reference to the current object. This is called explicit constructor invocation. A constructor of a superclass can be invoked from inside a constructor using the super keyword followed by parentheses in which arguments may be provided. The invocation of a superclass constructor must be the first statement in the subclass constructor so as to perform first the super class initialization. Otherwise, the superclass default constructor will be invoked implicitly.
A constructor of a class can be specified as private, protected, package, and public which specifies which classes are eligible to create instances of that class. When a constructor is private no other class can instantiate the class and only if the class provides public classes to instantiate the class, an object can be created. When a constructor is specified as protected, only subclasses can use it to create objects of the class. If a constructor is specified as public any class can create an object of the class using the constructor. Finally, a package constructor can be used only by classes within the same package to create objects of the class.
Example on constructors:
class Point
{
private double x, y;Point() // default constructor
{
x = y = 0.0;
}
Point(double x, double y) // constructor overloading
{
this.x = x;
this.y = y;
}public String toString() // toString method
{
return ("x = " + x + " y = " + y);
}
}class constructorsClasses
{
public static void main(String args[])
{
Point p1= new Point(), p2;
p2 = new Point(2.22,4.8);System.out.println("\n p1: " + p1);
System.out.println("\n p2: " + p2);
System.out.println();
}
}
Output:
p1: x = 0.0 y = 0.0
p2: x = 2.22 y = 4.8
If no values are provided to the variables of a class using either initializers or constructors a zero, '\u0000', false, or null value is assigned depending on the variable's data type.
The following example demonstrates the use of static and instance initializers.
Initializers example:
class Initialization1Output:
{
public static void main(String args[])
{
Point p = new Point();
System.out.println("Number of points = " + Point.pointsNumber);
System.out.println("(x,y) = (" + p.x + "," + p.y + ")") ;
}
}class Point
{
double x=200, y=100; // instance initializer
static int pointsNumber=1; // static initializer
}
Number of points = 1
(x,y) = (200.0,100.0)
However, these initializations can be done only
when using assignment statements, i.e. without the ability to call any
other method, or throw an exception. For such cases a static initialization
block can be used to initialize static members, while a constructor
is, in general, used for the initialization of instance members. Constructors
are called after the initializers have assigned the default values to the
member data.
A static initialization block is a block enclosed with curly braces with the keyword static before it. The static initialization blocks and the static initializers are called in order from left to right and from top to bottom.
Static initialization block example:
class PointOutput:
{
double x=200, y=100; // instance initializer
static int pointsNumber;static // static initialization block
{
pointsNumber = 1;
System.out.println("Inside static initialization block");
}
}
class Initialization2
{public static void main(String args[])
{
System.out.println("Inside main");
Point p = new Point();
System.out.println("Number of points = " + Point.pointsNumber);
System.out.println("(x,y) = " + p.x + "," + p.y + ")") ;
}
}
Inside main
Inside static initialization block
Number of points = 1
(x,y) = 200.0,100.0)
Java supports also instance initialization
blocks (or non-static initialization blocks) which are sometimes useful,
such as in anonymous classes where having constructors is not possible.
An instance initialization block is placed at the location where a new
object of the class is created. The non-static initializers are executed
upon the creation of an object before the invocation of the corresponding
constructor. The order of execution of instance initializers and initialization
blocks is again from left to right and from top to bottom.
An anonymous class is a class without a name that is defined within another class. At the same time that it is defined an instance of it is created using the new keyword. Since an anonymous class has no name it cannot have any constructors.
Member data (or member variables) are declared using the data type followed by the name of the variable. The data type can be any primitive or reference data type, while the name should be any legal Java identifier. In addition, the following attributes can also be specified:
access level: specifies the access level for this variable, which can be public, package, protected, and private. static: specifies that the variable is static (i.e. class) variable final: specifies that the value of the variable after it is assigned cannot be modified transient: indicates that the variable is transient, which is not yet fully specified volatile: indicates that the Java compiler should not perform certain optimizations on the variable
Member functions are typically
provided, as in C++, to operate on member data allowing data encapsulation,
hiding
data behind functions (methods). However, in Java global functions are
not allowable. Every function must be provided within a class definition.
Also externally defined member functions are not possible in Java,
since everything must be defined within a class. Java supports recursion,
allowing a function to call itself either directly (direct recursion),
or indirectly (indirect recursion) through another function.
A function has two parts, the function
declaration and the function body. The function declaration
must provide the return data type and the name of the function followed
by parentheses that enclose the parameters of the function.
A function may return a value or no value
in which case it is declared as void. A function that returns an
object of a class can return an object of any subclass of that class as
well. In addition, a function may have an interface as a return type, in
which case an object of any class that implements that interface may be
returned.
The function name should be any legal Java identifier. The name of a function can be the same as the name of a data member of the class. Java supports, as C++, function overloading allowing functions to have the same name as long as the individual functions with the same name differs in the number or/and type of the parameters. The signature of a function is its name together with the number and type of its parameters. Functions with different signatures, although with the same name, are allowable.
A function may have no or any number of arguments. A function with no arguments is defined using empty parentheses. An argument with the same name as a member variable of the class hides the member variable. In that case the reference this can be used. The latter, i.e. this, is a reference that refers to the object with which the member function has been invoked. The reference this may be used to pass a reference to the object that has invoked the member function, as an argument to the member functions. Similarly the reference super refers to the superclass of a class and can be used when a member variable or function of a superclass is hidden. In Java, it is not possible to pass a function (or a pointer to a function) as an argument to a function.
All arguments to functions in Java are passed by value, which means that primitive data type arguments and the actual references cannot be modified. The values of the parameters are copies of the values of the arguments passed to the function. Declaring a function parameter using the final modifier prohibits the modification of that parameter within the function.
A function declaration may also provide more information about it using any of the following attributes:
An implicit reference to the object with which a function is invoked, called this, is available in every non-class (i.e. non-static) function. It is used to explicitly refer to members of the object that have invoked the function, or when an object reference is required.access level: specifies the access level for this variable, which can be public, package, protected, and private. static: specifies that the function is static (i.e. class) function, i.e. that it is not associated with a certain object of the class abstract: indicates that the method is not implemented. Therefore, the class is abstract and cannot be instantiated. final: specifies that the function cannot be overridden by a subclass native: indicates that the function is implemented in another language (e.g. C++) synchronized: indicates that certain precautions should be taken to ensure that functions that operate on same data, do it in a threat-safe way. throws <exceptions>: specifies the checked exceptions that the function may throw
A function of a class with the name toString() that takes no arguments and returns a String is a special function. It allows the object to be used in a string concatenation using the + operator, e.g. in a println statement. Note that all the primitive data type variables are implicitly converted to String objects whenever they are used in String expressions.
In Java there is no need to worry about explicitly
destroying objects that are not needed anymore. Java provides a garbage
collector that periodically frees memory of objects that are no more being
referenced. When a variable that is used to reference to an object goes
out of scope or it is set to null, that object, if not referenced by any
other variable becomes eligible for garbage collection.
Example on member data and methods:
class Point
{
private static int num = 0; // static field
private double x, y; // non-static data members (fields)/* set methods */
public void setX(double x)
{
this.x = x;
}
public void setY(double yy)
{
y = yy;
}
public static void incrNum() // static method
{
num++;
}/* get methods */
public double getX()
{
return x;
}
public double getY()
{
return y;
}
public static int getNum() // static function
{
return num;
}public String toString() // toString method
{
return ("x = " + x + " y = " + y);
}
}
class methodsClasses
{
public static void main(String args[])
{
Point p1, p2 = new Point();
Point.incrNum();p1 = new Point();
p1.incrNum();p1.setX(1.1);
p2.setX(2.2);System.out.print("\nNumber = " + Point.getNum());
p1.setY(0.11111);
System.out.print("\n p1: x = " + p1.getX() + " y = " + p1.getY() );
System.out.print("\n p2: " + p2 );
System.out.println();
}
}
Output:
Number = 2
p1: x = 1.1 y = 0.11111
p2: x = 2.2 y = 0.0
Example on function overloading:
class methodsOverloadingOutput:
{
public static void main(String args[])
{
myPrint();
myPrint(3);
myPrint(1.7);
}public static void myPrint()
{
System.out.println(" Inside myPrint()");
}
public static void myPrint(int i)
{
System.out.println(" Inside myPrint(): i =" + i);
}
public static void myPrint(double x)
{
System.out.println(" Inside myPrint(): x = " + x );
}
}
Inside myPrint()
Inside myPrint(): i =3
Inside myPrint(): x = 1.7