The use of the term 'compilation' with computer programs means
'translation' from the source code we write to a form that can be executed.
There are several implementations of java compiler and
tools.
I will describe the tools from Sun's SDK (software development
kit).
The compiler is a program javac.
Java programs should be written and saved in in files with extent .java such
as Hello.java.
This file is compiled with the javac compiler:
javac Hello.java
The result is a new file named Hello.class
The Hello.class file is not a text file (it isn't composed of
'lines' of text), but it also doesn't contain machine code.
It contains an intermediate form of code called java
byte code.
The java byte code in the Hello.class file is similar to
machine code, but is not the same and cannot be executed directly
like programs that have been compiled (translated) to machine
code.
Instead, another program called java, opens the
Hello.class file and reads and executes the byte code
instructions in that file.
The java program plays the same role in executing
byte code as the hardware machine does in executing machine
instructions.
For this reason, the java program is referred to as the
java virtual machine.
The java program only works for .class files and assumes
that any file given to it will have the .class extent.
So the .class part of the name should be omitted when
executing Hello.class:
java Hello
Even the simplest java program requires quite a lot of
syntactic elements:
1 public class Hello
2 {
3 public static void main(String[] args)
4 {
5 System.out.println("Hello, world!");
6 }
7 }
Line 1:
All java code must be inside a class.
A file that contains the public class Hello
should be named Hello.java
Line 3:
Every java program executed by the java virtual
machine must have a method ( = function ) called
main.
The return type of main must be
void
main must be qualified to be public and static
The single parameter must be of type an array of
Strings.
Note: The name of the parameter to main is typically chosen to
be args, but can be any programmer chosen name.
To write and execute Java programs on your machine, you will
need to first install the java SDK.
Instructions are provided on the class Documents page.
Next, you will need a text editor or an IDE (Integrated
Development Environment) to write your .java file(s).
Do not use Microsoft Word or WordPad. Word inserts hidden
formatting and may capitalize first letters of java keywords
that it shouldn't.
Notepad would be ok, but there are much better choices if you
are going to use a simple text editor.
Although a bit more complicated to learn, an IDE has many
advantages initially and also as you become a more expert java
programmer.
I will recommend using the Eclipse IDE and will use it in
class examples.
Another very similar IDE is NetBeans, which can be downloaded
from Sun's site together with the SDK.
Both these IDE's provide a single place to:
- Write java programs
- Compile
- Execute
- Debug (E.g., step through execution one instruction at a time)
Instructions for installing and using Eclipse are also on the Documents page.
Note that the SDK should be installed first and then Eclipse.
Every variable or expression in Java has a type.
In Java, these types fall into exactly two categories:
- Basic types
- Class types
Variables of basic type have storage allocated of the correct
size to hold a value of that type.
Variables of class type have storage allocated only to hold a
reference to a value of that type.
References are essentially addresses and addresses are the
same size regardless of the value to which they refer.
The basic types are familiar numeric and boolean types:
boolean true, false
char 16 bit unicode representation of a character
byte 8 bit signed integer
short 16 bit signed integer
int 32 bit signed integer
long 64 bit signed integer
float 32 bit IEEE floating point number
double 64 bit IEEE floating point number
Using the "new" operator allocates memory on the "heap" for an
instance of the type.
Declaring a local variable in a method, allocates memory
for the variable on the call stack.
The base types are value types; that is, variables
declared of these types are assigned memory locations of the size
determined by the type without having to allocate memory
explicitly using "new".
1 /**
2 * A class to test the CashRegister class.
3 */
4
5 public class CashRegisterTester {
6
7 public static void main(String[] args) {
8 CashRegister register = new CashRegister();
9 double price1, price2;
10 double payment;
11 price1 = 29.50;
12 price2 = 9.25;
13 payment = 50.00;
14
15 register.recordPurchase(29.50);
16 register.recordPurchase(9.25);
17 register.enterPayment(50);
18
19 double change = register.giveChange();
20 System.out.printf("Your change is %.2f. Have a nice day!\n", change);
21
22 System.exit(0);
23 }
24 }
Local variables in the method main declared as the basic type double:
price1, price2, payment and change
The call stack is storage for local variables of methods.
Storage for local variables is allocated on the top of the
stack when a method begins and is removed from the top of the
stack when the method finishes (returns).
Local variable register is of type CashRegister
which is a user defined class type.
A class type has methods that can be called that require a
value of that type plus 0 or more additional parameters. The
number of parameters depends on the particular method.
The user defined CashRegister type has these methods:
void recordPurchase(double amt)
void enterPayment(double amt)
double giveChange()
A CashRegister value instance stores the total dollar amount
of all purchases until payment is made. For each call to
recordPurchase, this total is updated.
When enterPayment is called, another CashRegister value
stores the amount of the payment.
Finally when giveChange is called, the change is calculated
(payment - total_purchase) and is returned.
Each instance of the CashRegister type keeps its own stored
payment and purchase amounts.
To call an CashRegister instance method requires a
CashRegister instance.
The dot operator is required:
CashRegister register = new CashRegister();
register.recordPurchase(29.50);
^ ^
| |
CashRegister CashRegister
instance instance method
The basic types are value types; that is, variables
declared of these types are assigned memory locations of the
size determined by the type without having to allocate memory
explicitly using "new".
Assignment of value types makes
a copy of the value and stores the copy in the target of the
assignment.
short s1 = 512;
short s2;
s2 = s1;
s2++;
Now s2 is 513, but s1 is 512.
A Java class defines a type.
An instance of a class is a value of that type.
A variable declared as a class type is not allocated memory to
hold a value of the size of the type.
A variable declared of class type is automatically allocated
memory to hold a reference, either
null or the address of a class instance.
Declaring a local variable in a method of class type allocates
memory for the reference (address or null) only on the call stack.
Class instances can only be allocated using "new" and so
instance values are always located on the heap, not on the call stack.
Assignment of reference types does not make a copy of the value
referenced (a copy of the address is made);
StringBuffer s1 = new StringBuffer("abc");
StringBuffer s2;
s2 = s1;
s1.append("de");
Now s1 and s2 both reference the StringBuffer with value
"abcde"; there is only one StringBuffer.
There are only a few basic types, but Java library of class
types is huge and continues to grow.
This library is an Application Programmer Interface (API)
of class types that makes programming applications
more productive.
You don't have to build everything from scratch;
there is often some existing class type or types in the Java API
that can be used.
It isn't necessary or feasible to remember
all of the class types and all the methods for
each class type in the Java API.
The Java API documentation plus documentation on the java
compiler and other tools is readily available in html format on Sun's web
site and can also be downloaded to your machine.
http://docs.oracle.com/javase/6/docs/
The API index itself is at
http://docs.oracle.com/javase/6/docs/api/index.html
For integers, addition, subtraction and multiplication have the ususal
meanings and division truncates the decimal part. The mod
operator % computes the integer remainder
int x = 25, y = 10;
int ans;
ans1 = x + y; // ans1 is 35
ans1 = x - y; // ans1 is 15
ans1 = x * y; // ans1 is 250
ans1 = x / y; // ans1 is 2
ans1 = x % y; // ans1 is 5
int x = 5;
int y = 10;
double z = 3.4;
Post increment operators increment the variable after
computing its current value.
Expression |
Value |
Changed Variables |
x++ y++ z++ |
5 10 3.4 |
x is 6 y is 11 z is 4.4 |
int x = 5;
int y = 10;
double z = 3.4;
Pre increment operators increment the variable before
computing its value.
Expression |
Value |
Changed Variables |
++x ++y ++z |
6 11 4.4 |
x is 6 y is 11 z is 4.4 |
Two numeric but different base types: byte, short, long, float,
double cannot be added without first converting one of them so
that values of the same numeric type added.
Conversions can be made between any of these types with the
possible loss of precision due to the differences in size or
representation.
The types have an ordering:
byte -> short -> int -> long -> float -> double
A conversion of any one of these types to a type farther to the
right in the ordering is called a widening conversion.
A conversion of one type to a type to its left is called a
narrowing conversion.
Widening conversions are done automatically by the compiler.
byte b = 127;
short s;
s = b; // Ok. A widening conversion byte -> short
Narrowing conversions require a cast.
short s = 512;
byte b;
b = (byte) s;
The char type is the same memory size as a short.
A char value can be converted to a short and the other way
around as well.
However, neither is a widening conversion. Ordering including char:
byte -> short -> int -> long -> float -> double
/
/
char --/
That is, char -> int is a widening conversion. So
Ex1.
char ch = 'A';
int n;
n = ch; // Ok. A widening conversion.
n = 66;
ch = (char) n; // narrowing conversion requires a cast
But,
Ex2.
short s = 65;
char ch;
ch = (char) s; // Can be converted, but not widening; reqires cast
ch = 'B';
s = (short) ch; // Can be converted, but also not widening; reqires cast
Variable can be declared as constant so that no subsequent
changes are allowed. The purpose is to have a symbolic
name for a value that indicates more clearly its use.
Java syntax:
final int MAX_SCORE = 120;
MAX_SCORE = 100; // ERROR!
The String class type has many convenient instance
methods. For example,
- String replace(char oldchar, char newchar)
- String toUpperCase()
- String toLowerCase()
- String substring(int startPos, int endPos)
- boolean startsWith(String prefix)
- int length()
Remember, these methods cannot be called without using the
dot operator and a String instance.
Replace all i's with the character '1' and all s's with the
character '$' in the string "Mississippi".
/**
* Description: Exercise p2.9. Test string replace method.
*
* @author Glenn Lancaster
*
*/
public class ReplaceTester
{
public static void main(String[] args)
{
String original = "Mississippi";
String newstring;
String expected = "M1$$1$$1pp1";
newstring = original.replace('i', '1');
newstring = newstring.replace('s', '$');
System.out.println("Original String: " + original);
System.out.println("Replaced String: " + newstring);
System.out.println(" Expected: " + expected);
}
}
Note that the + operator with String operands is overloaded
to mean concatenation of strings.
The Java API class BigInteger allows "infinite" precision
integer arithmetic.
But the usual operator symbols: + - * / cannot be used.
Instead the BigInteger class has instance methods:
- BigInteger add(BigInteger second)
- BigInteger subtract(BigInteger second)
- BigInteger multiply(BigInteger second)
- BigInteger divide(BigInteger second)
- BigInteger pow(int exponent)
import java.math.BigInteger;
public class ex3 {
public static void main(String[] args) {
BigInteger bi;
bi = new BigInteger("2");
bi = bi.pow(1000);
System.out.println(bi);
}
}
Output:
107150860718626732094842504906000181056140481170553360744375038
837035105112493612249319837881569585812759467291755314682518714
528569231404359845775746985748039345677748242309854210746050623
711418779541821530464749835819412673987675591655439460770629145
71196477686542167660429831652624386837205668069376
For class types methods can be either
- instance methods, or
- static methods
So far we have looked only at instance methods.
To call either kind of method, you must use the dot
operator.
For an instance method, the operand to the left of the dot
must be an instance of the class.
But for a static method, no instance is needed. In that case,
the operand to the left of the dot is just the class name.
The Java Math class has many static methods
including:
- double sqrt(double x)
- int abs(int x)
- double abs(double x)
- double pow(double base, double exponent)
- int max(int x, int y)
- double max(double x, double y)
- int min(int x, int y)
- double min(double x, double y)
public class ex4
{
public static void main(String[] args)
{
double x = 2.0;
double y = Math.sqrt(x);
System.out.println("square root of " + x + " is " + y);
System.out.printf("square root of %.1f is %.6f\n", x, y);
}
}
Output:
square root of 2.0 is 1.4142135623730951
square root of 2.0 is 1.414214
System.out is an instance of type PrintStream
PrintStream methods
- void print(..)
- void println(..)
- void println()
- void printf(String fmt, ...)
The first two are designed to convert the argument to a suitable
character string.
The second inserts newline in the output.
The third only outputs a newline.
The printf method provides formatting of the output.
The number of parameters to printf depends on the number of
conversion specifications in the first parameter - the format string.
1
2 public class PrintfTester
3 {
4 public static void main(String[] args)
5 {
6 double x, y, z, sum;
7 x = Math.random() * 100;
8 y = Math.random() * 100;
9 z = Math.random() * 100;
10
11 sum = x + y + z;
12
13 System.out.printf("%10s %6.2f\n", "first", x);
14 System.out.printf("%10s %6.2f\n", "second", y);
15 System.out.printf("%10s %6.2f\n", "third", z);
16 System.out.printf("%10s ------\n", "");
17 System.out.printf("%10s %6.2f\n", "sum", sum);
18 }
19 }
Output:
first 93.60
second 3.13
third 49.83
------
sum 146.56
If the number of character positions in a format
specification is larger than needed, spaces are added.
By default spaces are added to the beginning of the value so
that it appears to be right justified in the
output.
To get left justification insert a minus sign; e.g. replace
all the %10s format specifications by %-10s in the previous example.
Then the output would be
first 93.60
second 3.13
third 49.83
------
sum 146.56
System.in is an instance of type InputStream
InputStream methods are not so convenient.
int read()
This method returns one byte from the input each time it is
called. It returns -1 at end of file.
How would you read the integers in a file?
Scanner is a type.
There are no predefined instances of this type and no useful
static methods..
We must declare a variable of this type and initialize it to
use the Scanner methods.
Scanner methods:
- String next()
- String nextLine()
- int nextInt()
- double nextDouble()
- boolean hasNext()
- boolean hasNextLine()
- boolean hasNextInt()
- boolean hasNextDouble()
import java.util.Scanner;
/**
* A class to test the CashRegister class.
*/
public class CashRegisterTester {
public static void main(String[] args) {
CashRegister register = new CashRegister();
Scanner in = new Scanner(System.in);
System.out.println("Price for first item:");
double price1 = in.nextDouble();
System.out.println("Price for second item:");
double price2 = in.nextDouble();
System.out.println("Payment amount:");
double payment = in.nextDouble();
register.recordPurchase(price1);
register.recordPurchase(price2);
register.enterPayment(payment);
double change = register.giveChange();
System.out.printf("Your change is %.2f. Have a nice day!\n",
change);
System.exit(0);
}
}
import java.util.Scanner;
1 public class ScannerInputTester
2 {
3 public static void main(String[] args)
4 {
5 Scanner in;
6 int first, second, larger;
7
8 in = new Scanner(System.in);
9 System.out.print("Enter first integer: ");
10 first = in.nextInt();
11 System.out.print("Enter second integer: ");
12 second = in.nextInt();
13 larger = Math.max(first, second);
14 System.out.printf("The larger of %d and %d is %d\n",
15 first, second, larger);
16 }
17 }
The JOptionPane class provides a graphical interface for
prompting for small amounts of input or for displaying
messages or relatively small amount of output.
import javax.swing.JOptionPane;
/**
* A class to test the CashRegister class.
*/
public class CashRegisterTester2 {
public static void main(String[] args) {
CashRegister register = new CashRegister();
double price1, price2, payment, change;
String reply;
reply = JOptionPane.showInputDialog("Price for first item:");
price1 = Double.parseDouble(reply);
reply = JOptionPane.showInputDialog("Price for second item:");
price2 = Double.parseDouble(reply);
reply = JOptionPane.showInputDialog("Payment amount:");
payment = Double.parseDouble(reply);
register.recordPurchase(price1);
register.recordPurchase(price2);
register.enterPayment(payment);
change = register.giveChange();
JOptionPane.showMessageDialog(null, "Your change is " + change);
System.exit(0);
}
}
-
This example uses yet another useful static method from
the wrapper class Double. It converts the String parameter,
str, to a double value and returns the double:
double parseDouble(String str)
-
At the end of main there is a call to the static method
exit in the System class:
void exit(int exitValue)
This call will terminate a program whenever it is
called. It can be placed in any method, not just main.
It is useful when using JOptionPane dialogs to avoid a
delay in program termination.
To create a user defined class type, the following steps are
usually needed:
- Choose an appropriate name for your class type
- Begin with the syntax for a class:
public class the_class_name_you_chose
{
}
- Decide what instance and/or static methods your class type
will have.
- Decide what variables you will need in the class for each
instance to "remember" and use between calls to its
methods.
- Write one (or more) constructors for your
class.
A constructor executes when an instance of your
class is created using the new operator.
A constructor's purpose is to properly initialize the
member variables before any of the methods are called.
- Write the methods.
- Write a separate class with a main method to test
your new class type.
We have already seen the testing class, CashRegisterTester
that should be in a file named CashRegisterTester.java
The CashRegister class should be in a separate file,
CashRegister.java
Recall the methods we want:
- void recordPurchase(double amt)
- void enterPayment(double amt)
- double getChange()
We need two double variables. One to store the total purchase
amount and one to record the payment amount.
Finally, we need a constructor to initialize these two
instance variables.
A constructor for a class looks like a member function
except:
- It has no return type (it isn't called; it is used with
new)
- The name of the constructor must be the same as the class name.
A constructor can have 0 or more parameters as needed.
A class can have multiple parameters
The CashRegisterTester uses the CashRegister type. It can
only use the members that are public.
The constructor and all the methods are public. So they are
accessible to the tester class.
The variables used to store the current purchase total and
the payment are private. The tester class cannot use the dot
notation to access these members.