Introduction to Computer Science

Start Lecture #2

1.8: Creating, Compiling and Executing a Java Program

Creating a Java Program

A Java program is created using a text editor. I use emacs. Others use vi, notepad, or a variety of alternatives. One possibility is the editor included with a Java IDE.

Compiling a Java Program

Java programs are compiled using a Java compiler. The standard compiler included with a JDK is called javac. To compile our Hello program (in the file Hello.java), one would write

    javac Hello.java
  
Javac translates Java into an intermediate form normally called bytecode. This bytecode is portable. That is the bytecode produced on one type of computer can be executed on a computer of a different type.

The bytecode is placed in a so-called class file, in this case the file Hello.class

Our C version of Hello, if contained in the file Hello.c, could be compiled via the command

      cc -o Hello Hello.c
    
The resulting file Hello is not portable. Instead it has instructions suitable for one specific machine type (and software system).

The Java Virtual Machine (JVM)

Portability of Java bytecode has been obtained by defining a virtual machine on which to run the bytecode. This virtual machine is called the JVM, Java Virtual Machine.

Each platform (hardware + software, e.g., Intel x86 + MacOS or SPARC + Solaris) on which Java is to run includes an emulator of this virtual machine. Somewhat ambiguously, the emulator of the Java Virtual Machine is itself also called the JVM.

The penalty for this portability is that executing bytecode by the (typically software) JVM is not as efficient as executing non-portable, so-called native, code tailored for a specific machine.

Executing a Java Program

Since essentially no hardware/OS can execute Java bytecode directly, another program is run and is given the bytecode as data. This program is typically included in any Java IDE. For the JDK the program is called java (lower case).

For our example the bytecode located in the file Hello.class is executed via the JDK command

    java Hello
  
(Note that we must write Hello and not Hello.class.)

1.9: (GUI) Displaying Text in a Message Dialog Box

  // Hello world in Java -- gui version
  public class HelloGui {
    public static void main (String[] args) {
    javax.swing.JOptionPane.showMessageDialog(null, "Hello, world.");
    }
  }

Java comes with a large library of predefined functions. The top example on the right shows how just changing the output function causes a dialog box to be produced. Naturally, this code only works on a graphical display.

Another difficulty is that actually explaining how the dialog box appears on the screen is quite complicated, involving widgets, fill-rectangle, and other graphics concepts.

  // Hello world in Java -- pedantic version
  public class HelloPedantic {
    public static void main (String[] args) {
    java.lang.System.out.println("Hello, world.");
    }
  }

In fact, our original hello example used a shortcut. The class System is actually found in the package java.lang (which is searched automatically by javac). The bottom example shows the program without using this shortcut.

1.A: Review Questions

These have answers on the web in the companion. See the book for details. I tried it and it works.

If you cannot understand an answer, ask! A good question for the mailing list.

Chapter 2: Elementary Programming

2.1: Introduction

2.2: Writing Simple Programs

Let's solve quadratic equations Ax2 + Bx + C. Computational problems like this often have the form

  1. Get the input
  2. Compute the output
  3. Print the results
  4. Do it again.

For our first example we will hard-wire the inputs and not do it again.

What is the input?
Ans: The three coefficients A, B, and C.

How is the output computed?
Ans: -B +- sqrt(B2-4AC)

What about sqrt of a negative number?
What about it? Mathematically, you get complex numbers. We will choose A, B, C avoiding this case. A better program would check.

    public class Quadratic1 {
        public static void main (String[] args) {
        double A, B, C;		// double precision floating point
        A = 1.0;
        B = -3.0;
        C = 2.0;
        double discriminant = B*B - 4.0*A*C;
        // We assume discriminant >= 0 for now
        double ans1 = (-B + Math.pow(discriminant,0.5))/(2.0*A);
        double ans2 = (-B - Math.pow(discriminant,0.5))/(2.0*A);
        System.out.println("The roots are " + ans1 + " and " + ans2);
        }
    }

The program is on the right. Note the variables are declared to have type double. This is the normal representation of real numbers in Java.

We can assign values to variables either when we declare them or separately. Both are illustrated in the example.

Note that the first two lines and the last two lines are the same as from the first example.

How does the println work? In particular, what are we adding?
Ans: The + is overloaded. X+Y means add if X and Y are numbers it means concatenate if X and Y are strings.

But in the program we have both strings and numbers.
When the operands are mixed, numbers are converted to strings.

The name double is historical. On early systems real numbers were called floating point because the decimal point was not in a fixed location but instead could float. This way of writing real numbers is often called scientific notation. The keyword double signifies that the variable would be given double the amount of storage as a would be given to a variable declared to be float.

2.3: Reading Input from the Console

The previous example was quite primitive. In order to solve a different quadratic equation it is necessary to change the program, recompile, and re-run.

In this section we will save the first two steps, by having the program read in the coefficients A, B, and C. Later we will use a loop to enable one run to solve many quadratic equations.

On the right is the program in a pedantic style. We show the program as it would normally be written below.

public class Quadratic2Pedantic {
  public static void main (String[] Args) {
    double A, B, C;
    double discriminant, ans1, ans2;
    java.util.Scanner getInput;
    getInput = new java.util.Scanner(java.lang.System.in);
    A = getInput.nextDouble();
    B = getInput.nextDouble();
    C = getInput.nextDouble();
    discriminant = B*B - 4.0*A*C;
    // We assume discriminant >= 0 for now
    ans1 = (-B + Math.pow(discriminant,0.5))/(2.0*A);
    ans2 = (-B - Math.pow(discriminant,0.5))/(2.0*A);
    java.lang.System.out.println("The roots are " + ans1
                                 + " and " + ans2);
  }
}

Note the following new features in this program.

import java.util.Scanner;
public class Quadratic2 {
    public static void main (String[] Args) {
    Scanner getInput = new Scanner(java.lang.System.in);
    double A = getInput.nextDouble();
    double B = getInput.nextDouble();
    double C = getInput.nextDouble();
    double discriminant = B*B - 4.0*A*C;
    // We assume discriminant >= 0 for now
    double ans1 = (-B + Math.pow(discriminant,0.5))/(2.0*A);
    double ans2 = (-B - Math.pow(discriminant,0.5))/(2.0*A);
    System.out.println("The roots are " + ans1 + " and
                       " + ans2);
  }
}

On the right we see the program rewritten in the style that would normally be used.

The above explanation is way more complicated that the program itself! For now it is fine to just remember how to read doubles. Other methods in the Scanner class include nextInt, nextString, and nextBoolean.

Homework: 2.1, 2.5

2.4: Identifiers

These are the names that appear when writing a program. Examples include variable names, method names, and object names. There are rules for the names.

2.5: Variables

As we have said classes contain data (normally called fields) and methods. Fields are examples of variables, but we haven't seen any yet. Later we shall learn that there are two kinds of fields, static and non-static.

Another kind of variable is the local variable, which is a variable declared inside a method. We have seen several, e.g. discriminant.

The final kind of variable is the parameter. We have seen one example so far, the args parameter always present in the main method.

2.6: Assignment Statements and Assignment Expressions

Many programming languages have assignment statements, which in Java are of the form

    variable = expression ;
  
Executing this statement evaluates the expression and places the resulting value in the variable.

This ability to change the value of a variable (so called mutable state) is a big deal in programming language design. Proponents of functional languages believe that imperative languages, such as Java, are harder to understand due to the changing state.

Java, like the C language on which the Java syntax is based, also includes assignment expressions, which are of the form

    variable = expression
  
(NO semicolon). An assignment expression evaluates the RHS (right hand side) expression, assigns the value to the LHS variable, and then returns this value as the result of the assignment expression itself.

    System.out.println(x = Math.pow(2,0.5));
     
     
     
    a = b = c = 0;
     
     
     
    a = 1 + (b = 2 + (c = 0));
  
The first example evaluates the square root of 2, assigns the value to x, and then passes this value to println.

The second example first performs c=0, which results in c becoming 0 and the value 0 returned. This 0 is then assigned to b and returned where it is assigned to a. Note the right to left evaluation.

The third example is ugly, confusing, and not recommended. It works as follows: c=0 is evaluated assigning 0 to c and returning 0. Then 2+0 is evaluated to 2, assigned to b, and returned. Then 1+2 is evaluated to 3, assigned to a, and discarded.

Java, again like C, uses = for assignment and == to test if two values are equal. Another common choice is to use := for assignment and = to test for equality.

2.7: Named Constants

We have seen constant numbers and constant strings. But these were literal constants; that is the value itself was used (e.g., 2 or "Hello, world.").

A string constant like "Hello, world." is certainly descriptive, but a numeric constant like 2 is not (does its usage signify that we are computing base 2, that our computer game program is playing 2-handed cribbage, or what?). In addition, if we wanted to change either constant, we would need to change all relevant occurrences.

Instead of explicitly writing the 2 or "Hello, world." at each occurrence, we can defined a named constant (a.k.a a symbolic constant) for each value.

    final int numberBase = 2;
    final int cribbageHands = 2;
    final String msg = "Hello, world.";
  
The first two lines on the right could be used in a two-handed cribbage program that somehow relied on base 2 representations. Then if the program was to be extended to 4-handed cribbage as well, we would have a clue where to look.

The final keyword says that definition gives the final value this identifier will have. That is, the identifier will not be assigned a new value. It is read-only or constant.

2.8: Numeric Data Types and Operations

Numerical values in Java come in two basic types, corresponding to mathematical integers and real numbers. However each of these come in various sizes.

Mathematical integers have four Java types.

Mathematical real numbers have two Java types

The difference between the four integer types and the four real types is the amount of memory used for each value. As the name suggests a byte is stored in a byte. A short is stored in two bytes; an integer is stored in four; and a long is stored in eight.

A float is stored in four bytes and a double is stored in eight.

For integers, allocating more storage permits a wider range of values.

Floating point is more complicated. The extra storage is used to extend the range of both the fractional part and the exponent. Recall that floating point numbers are represented in what is essentially scientific notation, so they store both a fractional part and an exponent (unlike customary scientific notation, the exponent represents a power of 2 not 10).