Grinding JavaAn IntroductionWritten by Shai Almog |
IntroductionI remember the first article I read about Java in Dr. Dobbs Journal: I reached the word interpreted and skipped over to the next article. Many programers treated Java the same way at first. Hype does not work on most of us and I felt at first that Java was mostly hype. When I was looking for a new job I figured Java appearing on my resume would look real good so I downloaded one of the early betas of the JDK [Java Developers Kit -- Ed] and started learning. I was not much impressed at first. As a person who grew on the knees of IDEs [Integrated Development Environments. Ed.] I was annoyed by this command line debugger most of all. But soon enough I found out that I needed a debugger much less than I ever needed one when writing C++ code. I actually found myself having fun learning a very simple and intuitive new language, with possibilities that almost reach the level of the hype surrounding it. Warning: don't read on if you know all of Java's basics, it will be a waste of your time. If you are well into C++ [or even C -- EDM] then browse through the article and look at the comments I made about the code. There are some interesting things for you. Next month I will introduce AWT and after that things will start getting more interesting. I intend to make the first few articles an introduction to Java. I chose the JDK 1.1 because it will become a standard by the time you will finish reading the introduction (knock wood). It's far better than JDK 1.02 (and by any other vendor it would have been a major version upgrade). I will teach Java applications rather than applets. [Java applets are small Java routines that only work within an applet browser, or web browser, and are usually subject to quite tight security. Java applications run by themselves, and usually have more freedom, so you can acomplish more with them. . Ed.] Most tutorials focus on applets and I feel applications will be more interesting to the OS/2 audience and that I will have less chance repeating myself. Debugging applications is easier and it's relatively easy to move application code to applet code (with considerations of applets limitations). I will assume that you know the hype but don't have Java background, and I will also assume that you have some minimal programing knowledge. If any of my terms seem confusing check out the Free On-line Dictionary of Computing or some of these Java related links I found useful:
And Yahoo of course has a huge Java section. Java hype and misconception versus reality
There is much more to say (eg multithreading, persistence, networking) but there are many other articles dealing with the those issues. Hello worldWe will start learning Java using the traditional hello world program: HelloWorld.java public class HelloWorld { public static void main(String argv[]); { // Prints Hello world. System.out.println("Hello world"); } }Things to notice:
Extending HelloWorld (variables, arrays, input and flow control)Hello world was very nice (not) but we need something more before we get to the heavy stuff. First we will have to make a small modification to HelloWorld. public class HelloWorld { public static void main(String argv[]); { new HelloWorld(); } public HelloWorld() // The class constructor. { System.out.println("Hello world"); // Prints Hello world. } }Some of you C++ programmers might have confused the main method with the constructor and the new HelloWorld() statement might not be clear. A constructor is a method that is called every time a new instance of the class is created (by using the "new" operator). Our program starts execution in the main method (as usual) where it allocates memory for the class HelloWorld and calls its constructor, notice the main method does not need the class to be allocated because it's a static method and does not use any of the variables (propertys) in the instance. The constructor goes on as before. Why was this change needed? A static function cannot reach the properties: imagine a program with no variables. VariablesJava supports the following native types: double - used for floating point numbers. float - used for floating point numbers. int - 32 bit round number. char - A unicode (16 bit) character. short - 16 bit round number. long - 64 bit round number. byte - 8 bit round number. boolean - Contains true or false.Another example: public class HelloWorld { public static void main(String argv[]); { new HelloWorld(); } public HelloWorld() // The class constructor. { System.out.println("The number is:" + Number); // Notice how java converts the type automatically } private int Number = 3; }Notice the keyword private. It means that no other class may use that property (in this case Number) and thus it protects us from depending on implementation specific concepts. This concept is called encapsulation and is one of the basic concepts of OO programming. Encapsulation is the idea of hiding the implementation, the detail of how the task is done, from the way you use the object, the interface and thus grouping functionality into manageable classes rather than hugh APIs. The best example of encapsulation is in GUI programming. Writing API specific code is a Herculean task with hundreds of APIs for each platform. Class libraries make this task easier by providing classes that wrap the API with simpler related methods. Then if you want to port your program all you have to do is change the hidden layer which is platform specific. That is why hiding the implementation is very important, so you or any other programer won't rely on specific code. Wrapping things up and only using the higher level wrappes is referred to as abstraction. if statementThe if statement is one of the most basic things of every programing language I know. An if statement is where your code enters a crossroad by testing a condition and choosing the correct path. An if statement accepts a conditional statement: if ([Conditional statement]) // statement to execute if the conditional statement is true. else // statement to execute if the conditional statement is false.If you wish to perform multiple commands as a result of an if statement you can use the following syntax: if ([Conditional statement]) { ... // as many statements as you want. // if the conditional statement is true. } else { ... // as many statements as you want. // if the conditional statement is false. }A conditional statement returns true or false, and they can be nested using conditional operators. This is quite a basic notion of programing and I assumed you have some knowledge of programing so I will not run too many examples by you. A simple example will speak in this case much better than any definition: int Number = 3; if (Number == 3) System.out.println("It is a 3"); else System.out.println("It is not 3");This program will obviously print out: It is a 3. Notice that the operator == was used and not =. The following operators are allowed in conditional statements:
LoopsJava supports loops almost (if not totally) identically to C. For loop - A for loop is designed to iterate to a known or measurable number while counting iterations. Syntax: for ([early variable initializations]; [Condition that will stop the loop]; [operation to perform with each iteration])Example: for (int I = 0;I < 100; I++) // the ++ operator increments a number by 1. The // -- operator is the decrements by 1. It's like I = I + 1; { ... // The body of code to be repeatedly performed }While loop - checks for a condition and then performs a body of code as long as the condition is valid. Syntax: while ([condition]) { ... // The body of code to be repeatedly performed }Example: while (I < 100) { ... // The body of code to be repeatedly performed }Do - Identical to the while, except that the first iteration of the loop will always be performed and then the condition will start getting checked after that. do { ... // The body of code to be repeatedly performed } while ([condition])Example: do { ... // The body of code to be repeatedly performed } while (i < 100)The following program will accept command line arguments and print them. public class PrintArguments { public static void main(String argv[]) { for (int i=0; i < argv.length; i++) new PrintArguments(argv[i]); } public PrintArguments(String Token) // The class constructor. { System.out.println(Token); } }Things to notice:
Exception handlingOne of Java's nice features are thread safe and predefined exceptions. Exception handling exists in an almost identical way in C++. What are exceptions? An exception is a point in the code where something out of the ordinary has happened and the regular flow of the program needs to be interrupted; an exception is not necessarily an error. A method which has run into such a case will throw an exception using the throw(ExceptionClass) method. When an exception is thrown it must be caught by a catch statement that should sit right after a try statement. That is a bit complicated, but to make things simpler I will explain why this complexity is really needed. To start a section of code which might fail or not follow through you start a try clause: try { // Section of code which might fail }After the try section there must exist one or more catch statments to catch some or all of the exceptions that can happen within the try block. [Exceptions that are not caught will be passed up to the next level, such as the function that called the one which threw the exception, and so on. . Ed.] try { // Section of code which might fail } catch (Exception1ThatCanHappen E) { // things to do if this exception was thrown.. } catch (Exception2ThatCanHappen E) { // things to do if this exception was thrown.. }This has the folowing advantages over handling your errors internally:
Arrayspublic class ArrayExample { public static void main(String argv[]) { // Default value of 30. int arraySize = 30; // Notice that in the if statement == is used to test quality. if (argv.length == 1) { Integer I = new Integer(argv[0].trim()); arraySize = I.intValue(); } new ArrayExample(arraySize); } public ArrayExample(int sizeOfArray) { charactersTyped = new byte[sizeOfArray]; try { System.in.read(charactersTyped); } catch (java.io.IOException E) { System.out.print("An I/O error has occured!"); System.exit(1); } String outString = new String(charactersTyped); System.out.println(outString); System.out.print("The third character is :" + (char)charactersTyped[2]); } byte charactersTyped[]; }Things to notice:
Inheritance, interfaces and polymorphismTo those of you who are used to C++ this section is really unneeded. I hope you know the basic OO concepts because I'm not going to explain them in depth here. Say you built a class called MyButton but MyButton only supports text labels and no image buttons. Let's say you (or someone else) wants to build an Image button. You can sit on your old button code and modify it and hack it into becoming an image button but then you will have a big and bloated class that does 2 distinct things. You could write a whole new class based on the old MyClass source, but then your old code that uses button might not be easy to convert back and forth with image button and you will have code duality between Image button and button, which means that every change you wish to add to both you will have to do in both of them. OO programing comes with the solution. You can inherit the original class and have all its functionality, and you can override some of the old functionality. A hello inheritance program will be the best example: class BaseClass // Base class not public so I // don't have to define it in a new file. { BaseClass() { System.out.println("BaseClass is constructed"); } void sayHello() { System.out.println("Ahalan from the base class"); } } public class HelloOO extends BaseClass { public static void main(String argv[]) { new HelloOO(); } HelloOO() { System.out.println("HelloOO is constructed"); sayHello(); } void sayHello() { System.out.println("Hello OO world"); } }The output of this program is: BaseClass is constructed HelloOO is constructed Hello OO worldBut say, I'd like to modify the functionality of the previous method, not replace it, how do I do that? The keyword "super" does it for me. The Java tutorial defines super as: super is a Java language keyword that allows a method to refer to hidden variables and overridden methods of the super class (parent class). To make this more visual: The inheritance mechanism actually creates a full instance of the class you are inheriting and adds on the properties of the subclass afterwards. A super is a pointer to the part which is the parent class that doesn't know of the sub classing [inheritance -- Ed]. void sayHello() { super.sayHello(); System.out.println("Hello OO world"); }Here super is a reference to the instance of the class you've inherited so in other words super.sayHello() will invoke BaseClass.sayHello() and not HelloOO.sayHello() The output of this modified program is: BaseClass is constructed HelloOO is constructed Ahalan from the base class Hello OO worldThis is all very nice, but wait there is more. Homomorphic class design is the paradigm based on the idea that every code that works with a base class should work with all the derived classes of that base class. This is the theory of polymorphism which means different instances of the same object can have different kinds of behavior. An example to is the best way to explain this so let's go back to the button example: class Button { public Button() { ... // code } public void displayButton() { ... // code } public void setLabel(String S) { ... // code } ... // more methods } class ImageButton extends Button { public void displayButton() { ... // code } public void setImage(String S) { ... // code } } class Toolbar { Button arrayOfButtons[] Toolbar() { ... // code } void addButtonToToolbar(Button B) { ... // code } ... // more methods }The following piece of code will work correctly: Toolbar T = new Toolbar(); Button TextButton = new Button(); T.addButtonToToolbar(TextButton); Button ImageButton = new ImageButton(); T.addButtonToToolbar(ImageButton);An image button behaves just like a text button, so it can pretend to be one even though it supports extra functionality. The other way around is not possible (in this example). I will not give an example but there exists a definition in Java called abstract. When a method is declared abstract it has to be overridden or else the class cannot be built. This is good for classes that are supposed to be general purpose classes so the user can derive from them to their classes and supply the functionality the class needs. There is also a Java keyword called final which means when applied to a method that that method cannot be overridden and when applied to a class that that class cannot be inherited. Interfaces are a very powerful concept which Java implements. Some people claim that interfaces are Java's replacement to multiple inheritance but they are not really. An interface is like a class which cannot inherit from a class but can inherit from another interface they cannot have method bodys, only abstract methods. However you don't have to specify that they are abstract. All the members of an interface are public. An interface can only include final static public variables. What good is an interface? Say you want code to interact, yet you don't want the same base classes and code to be used for basically different functions. For example: interface Picture { void showPicture(); public static final int NOT_JPEG = 2; public static final int NOT_GIF = 1; } class Gif implements picture { void showPicture() { ... // code } } class Jpeg implements picture { void showPicture() { ... // code } }This will work too: Picture P = new Gif(); if (P.err == P.NOT_GIF) P = new Jpeg(); P.showPicture(); the Vector classI will talk about the Vector class here because it's very simple and it'll help you understand the Java OO paradigm. A Vector is actually an array that can contain all types of objects and can grow and shrink. Vector is a member of the java.util package so in order to use a vector you will have to either: import java.util.Vector;Or import java.util.*;I very much recommend running javap java.io.Vector to see the list of methods that a vector supports. You can create a vector by simply building a new instance of class vector: Vector v = new Vector();You can have a vector with a predetermined size by building Vector v = new Vector(Size);You can resize a vector to a new size using the setSize method. v.setSize(Size);The capacity and size methods can give you valuable information of your space usage and the length of the vector. setElementAt(java.lang.Object,int) will make an element at a specified offset into the element given as a parameter: MyClass S = new MyClass(); v.setElementAt((Object)S,1);Notice the type casting to Object. Object is the most basic class in Java; all of Java's class inherit from it. I will explain in detail the structure of Object in a future article but for now try javap java.lang.Object. It should be very interesting. removeElementAt(int X) // will remove the element at offset X. v.removeElementAt(1);insertElementAt(java.lang.Object,int) will push an element into the array (without overriding any existing elements. MyClass S = new MyClass(); insertElementAt((Object)S,1);addElement(java.lang.Object) will add an element to the end of the vector and will enlarge it appropriately. MyClass S = new MyClass(); addElement((Object)S);boolean removeElement(java.lang.Object); Will return true or false upon success in removing the given element from the Vector. removeAllElements(); I think this method is quite clear. import java.util.Vector; public class VectorExample { public static void main(String argv[]) { new VectorExample(argv); } VectorExample(String argv[]) { int i; Vector v = new Vector(); for (i = 0; i < argv.length; i++) { v.addElement((Object)argv[i]); } if (v.size() >= 2) // If the number of elements in V is equal to or larger than 2. v.insertElementAt((Object)"Inserted Element",1); //Push an element into v. for (i = 0; i < v.size(); i++) System.out.println((String)v.elementAt(i)); } }Notice the type casting in the example, all objects must be converted to and from class Object. Notice the check of the size of the vector before insertion, the insert method will fail if the array is too small. In ConclusionWe learned about the most basic syntax and concepts of Java (there is much more in depth basic stuff). I did not mention threads but I'd like to delay them until we have covered a little more. I rushed us through this whole thing so we can get to the neat GUI AWT stuff next month, since I believe that by trying out practical examples you can learn much more than by stupid hello world programs (although there are some more coming next month). |