|
|
Grinding JavaBack to BasicsWritten by Shai Almog |
Back to basicsIn the old cheap karate B movies, the wise old Chinese man sits with his student and shows him how to catch a fly with chopsticks and then teaches him the basics of marshal arts. In essence the tutor is grabbing attention using a cheap trick and then goes back to teach the really important stuff, which is what I am trying to do right now (it's either this or Ed Wood where I'd have to wear a dress). In this article we will go back from the AWT focus and learn some basic things about Java. However now all our hello world applications will look better with the AWT look and feel. The basicsWhen you build an object in C++, its real structure is very simple. Your class is built by what you inherit and what you define within it. In Java it is slightly more involved. As you may have already noticed Java classes have functionality that seems to be a part of the language such as the method equal() which exists for every object in Java. These capabilities don't come out of thin air. In Java all classes are derived from java.lang.Object, and for every class you have a java.lang.Class instance. If you were to create a class that inherits from no class it will still be derived from java.lang.Object. This will sound very familiar to SmallTalk programmers out there but a bit fishy to C++ programmers. The reason for this behavior is so every Object in Java will have a certain standard behavior. java.lang.ObjectThe Object class contains the following capabilities (these are based on the Java API documentation):
java.lang.ClassEvery data type in Java has an instance of class Class to fit it. What does Class do? Every thing that Java can do that Object does not provide! I removed many of the methods in this class to make it easier to swallow. Except for the first two just browse over the rest. It is more important right now to learn the concept of this class rather than its capabilities which are what gives Java its power.
Let's make a small program that will demonstrate the power of the Class class:
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
public class DynamicLoader extends Frame implements ActionListener
{
public static void main(String argv[])
{
new DynamicLoader();
}
DynamicLoader()
{
setLayout(new BorderLayout());
buttonToolbar.setLayout(new FlowLayout());
buttonToolbar.add(loadButton);
buttonToolbar.add(exitButton);
add("South",buttonToolbar);
add("Center",message);
add("North",className);
exitButton.addActionListener(this);
loadButton.addActionListener(this);
pack();
show();
}
public void actionPerformed(ActionEvent E)
{
if (E.getSource() == exitButton) System.exit(0);
if (E.getSource() == loadButton)
{
try
{
String name = className.getText();
Class TargetClass = getClass().forName(name);
Object o = TargetClass.newInstance();
message.setText(o.toString());
}
catch (ClassNotFoundException C)
{
message.setText("Class not found!!!");
}
catch (InstantiationException C)
{
message.setText("Class cannot be created!!!");
}
catch (IllegalAccessException C)
{
message.setText("Class cannot be accessed!!!");
}
}
}
Label message = new Label();
TextField className = new TextField();
Button loadButton = new Button("Load");
Button exitButton = new Button("Exit");
Panel buttonToolbar = new Panel();
}
Try running this class with things such as java.awt.Frame. Don't forget to
give the full name of the class or it will not find it. Notice the
exceptions that I must catch.
A few things before we go onI did not mention all the keywords and terms available in Java, and now is a good time to do that. synchronized - In a multithreaded environment many problems can arise when one thread disturbs the work of another. The synchronized keyword allows us to hide some this complexity. When a method is declared synchronized only one thread can access it at a time, and when a property is declared synchronized only one thread can use it at a time. abstract - When a method is declared abstract it has no body. That means that it will be defined by a class that inherits this class. A class which has abstract methods is an abstract class which cannot be instantiated and can only be derived. This is similar to creating an interface. transient - A transient property/object is an object which is temporary or local. This is related to the object serialization and maybe to future persistence. When you wish to transfer a class over the net or into a file through a stream of data, there might be some members that you don't need to transfer (they are used internally only) you mark them as transient. protected - This keyword should be familiar to C++ programmers. Protected members may be accessed by all subclasses of the current class, but are not visible to classes outside the current package. final - The final keyword prevents overriding of members and subclassing when applied to a class. The reasons for this keyword are for both security and to prevent people from mistakenly overriding important members. friendly - The default access right given to members. The member is fully accessible within the current package but not at all outside the package. static - The static keyword should be familiar to C++ programmers. When applied to properties the static keyword means that the member is identical to all instances of the class, and when applied to methods it means that the method belong to the class but not to the instance, meaning they cannot modify or read non-static members, and they can be reached globally. I.e. when I use Color.red red is a static property of class Color. ThreadsJava does make multi threading much easier, but it's still a pain. That is why I've waited so long to introduce threading in Java. Threading in Java is built around a class and an interface: interface Runnable and class Thread. To implement runnable all you have to do is create a method called run which will run on the newly created thread. You can subclass Thread or you can create a new instance of it; I always create it manually. The classic thread racer program which shows how to set priorities and to kill threads is presented here. It creates three threads responsible for different canvases that compete against each other.
import java.lang.*;
import java.awt.*;
import java.awt.event.*;
public class ThreadRacer extends Frame implements ActionListener
{
public static void main(String argv[])
{
new ThreadRacer();
}
ThreadRacer()
{
setLayout(new BorderLayout());
racers.setLayout(new FlowLayout());
racer1.setColor(Color.blue);
racer2.setColor(Color.red);
racer3.setColor(Color.yellow);
racers.add(racer1);
racers.add(racer2);
racers.add(racer3);
killButton.setEnabled(false);
buttonToolbar.setLayout(new FlowLayout());
buttonToolbar.add(exitButton);
buttonToolbar.add(startButton);
buttonToolbar.add(killButton);
buttonToolbar.add(suspendButton);
exitButton.addActionListener(this);
startButton.addActionListener(this);
killButton.addActionListener(this);
suspendButton.addActionListener(this);
add("South",buttonToolbar);
add("North",racers);
pack();
show();
}
public void actionPerformed(ActionEvent E)
{
if (E.getSource() == exitButton)
{
System.exit(0);
}
if (E.getSource() == startButton)
{
threads[0] = new Thread(racer1);
threads[1] = new Thread(racer2);
threads[2] = new Thread(racer3);
threads[1].setPriority(Thread.MIN_PRIORITY);
threads[2].setPriority(Thread.MIN_PRIORITY + 5);
for (int i = 0; i < 3; i++)
threads[i].start();
startButton.setEnabled(false);
killButton.setEnabled(true);
}
if (E.getSource() == killButton)
{
for (int i = 0; i < 3; i++)
threads[i].stop();
startButton.setEnabled(true);
killButton.setEnabled(false);
}
if (E.getSource() == suspendButton)
{
threads[2].suspend();
}
}
Racer racer1 = new Racer(),
racer2 = new Racer(),
racer3 = new Racer();
Thread [] threads = new Thread[3];
Button exitButton = new Button("Exit");
Button startButton = new Button("Start racing");
Button killButton = new Button("Kill threads");
Button suspendButton = new Button("Suspend thread 2");
Panel buttonToolbar = new Panel(),
racers = new Panel();
}
class Racer extends Canvas implements Runnable
{
Racer()
{
setSize(100,100);
}
public void run()
{
while (true)
{
counter++;
repaint();
if (counter > 100) counter = 0;
}
}
public void paint(Graphics g)
{
g.setColor(barColor);
g.fill3DRect(0,100 - counter,100,100,true);
}
public void setColor(Color barColor)
{
this.barColor = barColor;
}
private Color barColor;
private int counter = 0;
}
Things to notice:
If you wish to learn more of the threads capabilities try running javap java.lang.Thread. StreamsWhat is a stream? The Oxford dictionary describes a stream as: Flow (of liquid, people). C++ programmers should be well aware of streams, in Java they are quite similar but much more generic. Java uses streams to control a flow of data from an origin i.e. data from a disk file is read through a stream, as is data from a network and such. We have used streams before, when we used the System.out.println method, we were writing into a stream. Java has a huge selection of types of streams, we will go over the main choices and explain the differences:
To demonstrate I will write a small class that reads standard windows INI files and acts on their commands. The parsing of INI files can be very annoying but the StreamTokenizer class can make this very simple.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class iniFileReader extends Frame implements
ActionListener,WindowListener
{
public static void main(String argv[])
{
new iniFileReader();
}
public iniFileReader()
{
setLayout(new BorderLayout());
add("North",inifileName);
add("Center",output);
add("South",buttonLoad);
buttonLoad.addActionListener(this);
addWindowListener(this);
pack();
show();
}
public void actionPerformed(ActionEvent E)
{
if (E.getSource() == buttonLoad)
loadIniFile(inifileName.getText());
}
private void loadIniFile(String fileName)
{
try
{
// Remove all the messages on the output panel.
output.removeAll();
// FileReader opens a stream to a file.
FileReader iniFile = new FileReader(fileName);
// Tokenizing the file stream.
StreamTokenizer iniFileTokens = new StreamTokenizer(iniFile);
// The id of the current token.
int currentToken = iniFileTokens.nextToken();
// Treats the = operator as a token.
iniFileTokens.wordChars('=','=');
// Treats the ; char as a comment.
iniFileTokens.commentChar(';');
// Treat the end of line char as a token.
iniFileTokens.eolIsSignificant(true);
// This will be used for output.
String currentLabel = "";
while (currentToken != StreamTokenizer.TT_EOF)
{
// Get the next word.
currentToken = iniFileTokens.nextToken();
// if it's the end of line.
if (currentToken == StreamTokenizer.TT_EOL)
{
// Add this label to the output panel.
output.add (currentLabel);
currentLabel = new String("");
}
else
if (iniFileTokens.sval == null)
currentLabel = currentLabel + " " + iniFileTokens.nval;
else
currentLabel = currentLabel + " " + iniFileTokens.sval;
}
}
catch (Exception e)
{ // Catching a generic exception and displaying a generic message.
output.add("File error :" + e.getMessage());
}
output.setSize(200,400);
pack();
}
public void windowOpened(java.awt.event.WindowEvent e)
{
}
public void windowClosing(java.awt.event.WindowEvent e)
{
System.exit(0);
}
public void windowClosed(java.awt.event.WindowEvent e)
{
}
public void windowIconified(java.awt.event.WindowEvent e)
{
}
public void windowDeiconified(java.awt.event.WindowEvent e)
{
}
public void windowActivated(java.awt.event.WindowEvent e)
{
}
public void windowDeactivated(java.awt.event.WindowEvent e)
{
}
TextField inifileName = new TextField("c:\\OS2\\mdos\\winos2\\system.ini");
List output = new List(30,true);
Button buttonLoad = new Button("Load");
}
Things to notice:
String, StringBuffer and String tokenizerWe have used the String class a lot. Whenever we use the "" operator we create an instance of the String class. Java's Strings are very powerful, yet quite eccentric in a way. Most tutorials say that you cannot change a string which is slightly confusing. A String cannot be changed to a different length but it can be replaced with another string. There exists a StringBuffer class whose length can change. A string supports the following methods:
ConclusionsWell this time wasn't as fun as the last time but we are getting somewhere. We still haven't finished the basics, but from now on I feel that you should have a certain feel for Java so I'll make our purpose slightly more interesting. Next time we will go into java.net. We will build a program called the WWW utility, which (hold on to your seats) will do something useful! Til next month... good night. |