Issue #003
April, 1996


Contents:

Global Variables and Functions in Java
How to Do Linked Lists in Java
Comparing C/C++ With Java Part 3 - Operator Overloading
Introduction to Applet Programming Part 1 - Handshaking Protocols
Java Program Packaging Part 1 - CLASSPATH and Packages


INTRODUCTION

In this issue we'll talk about using global variables in Java
programs, show a simple technique for using linked lists, talk about
operator overloading, start a series about writing Java applets, and
finally present the first part of a series on how Java programs are
packaged.


GLOBAL VARIABLES AND FUNCTIONS IN JAVA

Java has no global variables or functions, unlike some other common
languages.  Every variable and function must be part of some class.
Within a class, a variable or function ("method") may be a regular
member of that class, or may be a class variable or class method.

Class methods and variables do not operate on particular object
instances of a class.  A class method is typically used as a utility
function within the class, while a class variable is shared by all the
instances of the class.  For example, if you're writing a Date class
to represent calendar dates, a class method might be used for the
method that determines whether a given year is a leap year.

Using class methods and variables, it is possible to synthesize
variables and methods somewhat similar to globals.  For example, you
can say:

        // file "Global.java"

        public final class Global {
                public static int x = 37;
                public static int f()
                {
                        return 47;
                }
        }

        // file "globtest.java"

        public class globtest {
                public static void main(String args[])
                {
                        int i = Global.x + Global.f();

                        System.out.println("i = " + i);

                        Global.x = 0;

                        System.out.println("x = " + Global.x);
                }
        }

"static" is the keyword used to denote that methods or variables are
class ones.  The Global class is declared as final, meaning that it
cannot be extended (derived from).  The class variable and method
names in Global are denoted by prepending "Global." to them.

If we wanted to get a bit fancier, we could add a line to Global:

        private Global() {}

This declares a private constructor for Global, meaning that anyone
who tries to create an object instance of Global will get an error
message at compile time.  The error will occur because they are trying
to create an object whose constructor is inaccessible.  This is
reasonable behavior since we don't care about creating object
instances of Global; it's just a wrapper for some variables and
methods.

Another change that could be made would be to have all access to class
variables in Global done through methods:

        private static int x = 47;
        public static void setx(int i) {x = i;}
        public static int getx() {return x;}

This makes it easy to trap all changes to the global variable.

A technique similar to that shown in this section is possible in C++,
but is not required.  C has no similar mechanism at all, though you
can enforce your own rules via naming conventions and access functions.

It is possible to get into a long argument about the desirability of
global variables.  They are best avoided, except to track
application-wide information, such as the current program state or
resources that are to be shared between threads.  The Java I/O system
uses the technique illustrated here to set up System.out for use in
code like:

        System.out.println("xxx");

System is a final class with a private constructor, and out is a class
variable defined within that class.


HOW TO DO LINKED LISTS IN JAVA

Java has no user-visible pointers, so how would you do a linked list?
Each element needs to point to the next one, doesn't it?

Well, fortunately there is a way, illustrated using this brief example:

        // source file link.java

        public class link {
                public int value;              // value of element
                public link next;              // reference to next
        
                // constructor
                public link(int n, link ln)
                {
                        value = n;
                        next = ln;
                }

                public static void main(String args[])
                {
                        // initialize list head
                        link head = null;

                        // add some entries to list
                        for (int i = 1; i <= 10; i++)
                                head = new link(i, head);

                        // dump out entries
                        link p = head;
                        while (p != null) {
                                System.out.println(p.value);
                                p = p.next;
                        }
                }
        }

Java does not have pointers, but instead uses implicit references.  A
line like:

        link next;

does not actually declare an object instance of class link, but rather
a reference to an object instance.  The line:

        head = new link(i, head);

creates a new element for the list, sets its value, and then sets the
object reference in "next" to point at the old list head (this
approach means that the last element inserted will be at the head of
the list).  Saying:

        p = p.next;

simply picks up the "next" reference from the current node and makes
it the current element being worked on.

When we're done using this list, we can simply leave the list with all
its elements lying around -- garbage collection will eventually
reclaim it.

If what you really want to do in a Java application is manage a list
of numbers, there are higher-level techniques in the language and
library (such as the Vector class) for doing so more cleanly than the
approach illustrated here.  This example shows some of what can be
done underneath to implement the higher-level schemes.


COMPARING C/C++ WITH JAVA PART 3 - OPERATOR OVERLOADING

In C++, code like this:

        class A {
        public:
                void operator+=(int);
        };

        void f()
        {
                A a;

                a += 187;
        }

is legal.  The operator "+=" has been overloaded to have a special
meaning when its first operand is a class object.  This usage is
equivalent to:

        a.operator+=(187);

that is, is a member function call on the object instance.

Java does not have operator overloading.  But you may have seen
sequences like:

        public class test1 {
                public static void main(String args[])
                {
                        String s1 = "abc";
                        s1 += "def";
                }
        }

which are perfectly legal.  Given that in C and C++ "+=" only works on
arithmetic or pointer types, and Java has no operator overloading, why
is this legal?

The answer is that in Java, the String type is part of the language
proper.  String methods are defined in libraries, just as in other
languages, but Strings are actually in the language itself.  When +=
is encountered, a call to the proper method is substituted.  We can
verify this by disassembling the compiled bytecodes:

        $ javac test1.java

        $ javap -c test1

This results in:

        Method void main(java.lang.String [])
        0 ldc #2 <String "abc">
        2 astore_1
        3 aload_1
        4 new #3 <Class java.lang.StringBuffer>
        7 dup
        8 invokenonvirtual #8 <Method java.lang.StringBuffer. \
                <init>()V>
        11 swap
        12 invokevirtual #9 <Method java.lang.StringBuffer.append \
                (Ljava/lang/String;)Ljava/lang/StringBuffer;>
        15 ldc #1 <String "def">
>>>>>   17 invokevirtual #9 <Method java.lang.StringBuffer.append \
                (Ljava/lang/String;)Ljava/lang/StringBuffer;>
        20 invokevirtual #6 <Method java.lang.StringBuffer.toString \
                ()Ljava/lang/String;>
        23 astore_1
        24 return

A bit of light reading!  From studying the bytecodes, we can tell what
actually happens when += is used.

Operator overloading is one of the more requested new features for
Java.  Adding it would yield expressiveness and notational convenience
to the language, at the cost of making it harder to read and follow
code.  It's quite easy in C++ to stumble across expressions using
overloaded operators, where the expression usage is so obscure that it
is very difficult to understand what is going on.  The most extreme
case of operator usage is the language APL, famous for its one-line
programs.


INTRODUCTION TO APPLET PROGRAMMING PART 1 - HANDSHAKING PROTOCOLS

In newsletter #001 we talked about applets a bit, and presented a
simple example of one.  A Java applet is not a standalone program but
one that executes in a specific context, that of a Web browser.
Before we get into the details of applet programming in future issues,
it might be worth illustrating some of the handshaking that goes on
between an applet and its controlling environment.  Normally an applet
is executed by a browser, though in the Java Development Kit there's
also a tool called "appletviewer" for this purpose.

But in our presentation here, we're going to present an applet with an
attitude -- an applet with a main() method that shows what happens
when an applet is executed.  The annotated code is as follows:

        // source file ga.java

        import java.awt.*;
        
        // An applet normally runs within an instance of a Frame, a
        // windowing object.  We subclass Frame so that we can trap
        // frame events, notably the event that kills a frame.  All
        // other events are passed to the superclass.
        
        class AppFrame extends Frame {
        
                // constructor - pass to superclass
                public AppFrame(String s)
                {
                        super(s);
                }
        
                // handle a frame event
                public boolean handleEvent(Event e)
                {
                        // see if they want to destroy window
        
                        if (e.id == Event.WINDOW_DESTROY) {
                                System.exit(0);
                                return true;
                        }
        
                        // pass to superclass if not handled
        
                        return super.handleEvent(e);
                }
        }
        
        // Here we extend the standard applet class in the Java
        // library.  This particular applet graphs the function
        // y = x^2.
        
        public class ga extends java.applet.Applet {
         
                // Y = X*X function
                private int f(int x)
                {
        
        // For reasons of personal taste we move the X,Y
        // origin from the upper left to the lower left
        // of the frame.  We have to retrieve the height
        // and width each time because they may change due
        // to frame resizing.
        
                        int h = size().height;
                        int w = size().width;
                        int w2 = (w - 1) * (w - 1);
                        double perc = (double)(x * x) / w2;
                        int amount = (int)(h * perc + 0.5);
        
                        return h - amount;
                }
        
        // The paint() method is called whenever the frame
        // needs to be updated.
        
                // paint method
                public void paint(Graphics g)
                {
                        int w = size().width;
        
        // We iterate across the frame width, computing
        // a Y for each X value and drawing it.
        
                        for (int x = 0; x < w; x++)
                                g.drawLine(x, f(x), x + 1, f(x + 1));
                }
        
                public static void main(String args[])
                {
        
        // We create an object instance of our applet.
        
                        // generate an instance of the applet
        
                        ga g = new ga();
        
        // We init and start the applet.  init() and start() are
        // methods that are found in the superclass.  They may be
        // overridden or not as desired by an applet.
        
                        // start it
        
                        g.init();
                        g.start();
        
        // Here we assign the applet to a frame, within which
        // it will run.
        
                        // put that applet in a frame
        
                        AppFrame f = new AppFrame("Test");
                        f.add("Center", g);
                        f.resize(400, 400);
        
                        // show the frame contents
        
        // We display the frame contents.
        
                        f.show();
                }
        }

The contents of main() illustrate the protocol used by a browser.  An
applet has certain methods, such as init() and start(), that
constitute its interface with the browser.


JAVA PROGRAM PACKAGING PART 1 - CLASSPATH AND PACKAGES

In a language like C or C++, the compilation model is fairly simple.
You compile a source file to an object file, and then later invoke a
linker to combine the object files with libraries into an executable
program.  More recently, shared libraries and so forth have been used
in the compilation model.

Java is a bit different in its approach.  We will be describing how it
handles program packaging and compilation in this and subsequent
issues.

The first thing to mention is that the Java compiler (javac) will
compile more than just the one source program given to it on the
command line.  It will go off and do other compilation as necessary.
The result of compilation is an xxx.class file, containing the
bytecodes and a description of the interface (set of methods and so
on) offered by the class contained within.

A public class should be defined within a file of the same name as the
class, with lower/upper case significant.  A public class uses the
keyword "public".  An example of a public class is given in the above
example on applets.  "ga" is a public class, "AppFrame" is not.  We
will mention more about public classes in a moment.  A Java source
file may contain only one public class definition.

The next item of importance is the CLASSPATH environment variable.
This is a set of directories that is used by the compiler and
interpreter to find classes.  For example, in a Windows NT
installation, the setting might be:

        CLASSPATH=".;d:/java/lib"

meaning that the current directory and then the directory d:/java/lib
are searched.  In UNIX the separator is ":" instead of ";".

Searched for what?  Source files, class files, and packages.  What are
packages?  Packages are groupings of related classes.  If I say:

        // file A.java

        package X;

        public class A {}

        // file B.java

        package X;

        public class B {}

then A and B are grouped in the package X.  A somewhat similar feature
in C++ is namespaces.

Packages are tied in with the CLASSPATH variable and the file system.
Declaring a package X as in the example means that somewhere along the
CLASSPATH directories there will be a directory X, with files A.java,
B.java, A.class, and B.class in it.  If the current directory is first
in the CLASSPATH list, then this means creating subdirectories of the
current directory, each subdirectory as the name of a package.

This works for system directories as well.  For example, looking under
d:/java/lib, there are directories java/applet, java/awt, java/io,
java/lang, and so on.  These tie in directly with import directives of
the form:

        import java.io.*;

        import java.awt.*;

and so on.  Note that:

        import java.lang.*;

is supplied implicitly and so does not have to be specified by the
programmer.  "*" means to import all classes in the package.

Package names can be used to qualify program entities.  For example, I
can say:

        java.lang.System.out.println("Howdy!");

In fact, there is some discussion about making the highest levels of
the package hierarchy correspond to Internet domain names, as in:

        COM.glenmccl.java.lang.System.out.println("Howdy!");

If this is done, then you won't have to worry about creating packages
and classes that interfere with those produced by others!

We mentioned above the distinction between public and non-public
classes.  Non-public classes in packages cannot be imported into a
program.  For example, this sequence is illegal:

        // file y1.java in Z/y1.java relative to current directory

        package Z;

        /*public*/
        class y1 {}

        // file y2.java in current directory

        import Z.*;

        public class y2 {
                public static void main(String args[])
                {
                        y1 y = new y1();
                }
        }

To wrap up this discussion for now, here is a longer example.  There
are two classes that do statistical analysis, one for descriptive
statistics like mean and standard deviation and the other for doing
correlation.  Don't worry too much if you don't know statistics; this
example is really about packaging.

We use a package called Stat for grouping these classes.

        // file Stat/descr.java in subdirectory

        package Stat;
        
        public class descr {
                private long n;         // count of numbers seen
                private double x;       // sum of X
                private double x2;      // sum of X^2
        
                // constructor
                public descr()
                {
                        n = 0;
                        x = x2 = 0.0;
                }
        
                // add a number to the pool
                public void add(double d)
                {
                        n++;
                        x += d;
                        x2 += d * d;
                }
        
                // retrieve the count of numbers seen
                public long cnt()
                {
                        return n;
                }
        
                // return mean (average)
                public double mean()
                {
                        if (n < 1)
                                throw new ArithmeticException();
                        return x / (double)n;
                }
        
                // return standard deviation
                public double stdev()
                {
                        if (n < 2)
                                throw new ArithmeticException();
                        double d1 = (double)n * x2 - x * x;
                        double d2 = (double)n * (double)(n - 1);
                        return Math.sqrt(d1 / d2);
                }
        }

        // file Stat/corr.java in subdirectory

        package Stat;
        
        public class corr {
                private long n;         // number of values seen
                private double x;       // sum of X
                private double y;       // sum of Y
                private double x2;      // sum of X^2
                private double y2;      // sum of Y^2
                private double xy;      // sum of X*Y
        
                // constructor
                public corr()
                {
                        n = 0;
                        x = y = x2 = y2 = xy = 0.0;
                }
        
                // add in a pair of numbers
                public void add(double a, double b)
                {
                        n++;
                        x += a;
                        y += b;
                        x2 += a * a;
                        y2 += b * b;
                        xy += a * b;
                }
        
                // return count
                public long cnt()
                {
                        return n;
                }
                
                // get correlation
                public double getcorr()
                {
                        if (n < 2)
                                throw new ArithmeticException();
                        double d0 = (double)n * xy - x * y;
                        double d1 = Math.sqrt((double)n * x2 - x * x);
                        double d2 = Math.sqrt((double)n * y2 - y * y);
                        return d0 / (d1 * d2);
                }
        
                // get a for y = ax + b
                public double geta()
                {
                        if (n < 2)
                                throw new ArithmeticException();
                        return ((double)n * xy - x * y) /
                            ((double)n * x2 - x * x);
                }
        
                // get b for y = ax + b
                public double getb()
                {
                        if (n < 2)
                                throw new ArithmeticException();
                        return y / (double)n - x / (double)n * geta();
                }
        }

        // file stest.java in current directory

        import Stat.*;
        
        public class stest {
                public static void main(String args[])
                {
        
                        // test descriptive statistics
        
                        descr sd = new descr();
                        for (int i = 1; i <= 10; i++)
                                sd.add((double)i);
                        System.out.println("count = " + sd.cnt());
                        System.out.println("mean = " + sd.mean());
                        System.out.println("std dev = " + sd.stdev());
        
                        // test correlation
        
                        corr co = new corr();
                        for (int j = 1; j <= 10; j++)
                                co.add((double)j, (double)j * 2.5 + 9.0);
                        System.out.println("count = " + co.cnt());
                        System.out.println("correlation = " + co.getcorr());
                        System.out.print("y = " + co.geta());
                        System.out.println("x + " + co.getb());
                }
        }


ACKNOWLEDGEMENTS

Thanks to Thierry Ciot, Irv Kanode, Mike Paluka, and Alan Saldanha for
help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com
with this line as its message body:

subscribe java_letter

Back issues are available via FTP from:

        rmii.com /pub2/glenm/javalett

or on the Web at:

        http://www.rmii.com/~glenm

There is also a C++ newsletter.  To subscribe to it, say:

subscribe c_plus_plus

using the same majordomo@world.std.com address.

-------------------------

Copyright (c) 1996 Glen McCluskey.  All Rights Reserved.

This newsletter may be further distributed provided that it is copied
in its entirety, including the newsletter number at the top and the
copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional Computer Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmii.com /pub2/glenm/javalett (for back issues)
Web: http://www.rmii.com/~glenm
