4. Files and Streams
Introduction
Now that we have laid
the groundwork for developing servlets, let’s get back to the basics. This
chapter carries on from where we left off in the first two chapters. It details
a few more features of the Java Programming language.
Let’s understand the
first program in this chapter, where we have two simple classes.
zzz.java
import java.applet.*;
public class zzz extends Applet {
public void init()
{
xxx a,b;
a = new xxx();
System.out.println(a.i);
b = new xxx();
System.out.println(b.i);
}
}
class xxx {
public int i = 6;
xxx()
{
i++;
System.out.println(“In Const xxx “ + i);
}
}
C:\javaprg>appletviewer a.html
In Const xxx 7
7
In Const xxx 7
7
You can have as many
classes as you like in a file, but only one of them can be declared public. You
will get an error if you make more than one class public. Add public to the xxx
class as well and it will display an error as shown below.
C:\javaprg>javac zzz.java
zzz.java:14: Public class xxx must be defined in a file called “xxx.java”.
public class xxx
^
1 error
In this program, class
zzz is declared as public but class xxx is not. a and b are two objects that
look like xxx. Let us remind you that here you do not call the constructor; it
is called by new at the time the object is created. The next line is, a=new
xxx(). In the constructor, i, which has the value 6, will now become 7. The
next line, System.out.println prints the value of i as 7. Hence you see the
output as
In Const xxx 7
C:\javaprg>appletviewer a.html
In Const xxx 7
7
In Const xxx 7
7
The statement b=new
xxx() creates one more variable named i. This is because new creates the
variables again. a.i and b.i will both have the same value. A point to be noted
here is that the functions don’t get created again. Functions can be shared but
not variables.
The next example
includes the word static which precedes the variable i.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
public void init()
{
xxx a,b;
a = new xxx();
System.out.println(a.i);
b = new xxx();
System.out.println(b.i);
}
}
class xxx
{
public static int i = 6;
xxx()
{
i++;
System.out.println(“In Const xxx “ + i);
}
}
C:\javaprg>appletviewer a.html
In Const xxx 7
7
In Const xxx 8
8
When you say static
and run the program, you will notice that a.i displays 7 and b.i displays 8.
This means that i in xxx gets created only once. In the previous example, where
the word ‘static’ was not included, if you had created 100 instances of xxx
there would have been 100 i’s. Remember, the code is not replicated each time
you say new. It is only the variables that get recreated.
Functions are stored
in one area of memory and variables in another. Each time you say new, it
checks to see if the function exists in memory. If it exists, then the function
isn’t added. In other words, functions are loaded into memory only once, but
the variables within the class are created afresh each time.
An object is an
instance of a class and when a class is instantiated, the variables are created
afresh. i as a variable is now related to the object and not to the class.
Whereas static variables have nothing to do with the object, they go with the
class. You don’t have to say new to access the static variable. This is shown
in the next program.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
xxx a;
public void init()
{
System.out.println(a.i);
}
}
class xxx
{
public static int i = 9;
}
C:\javaprg>appletviewer a.html
9
In this program, ‘a’
looks like xxx. We have not used new anywhere. We have a static variable i in
the class xxx. System.out.println with a.i will print 9 on the screen. Here, if
we make ‘a’ local, the compiler will return with an error saying that it has
not been initialized.
public void init()
{
xxx a;
System.out.println(a.i);
}
The compiler error
will be:
C:\javaprg>javac zzz.java
zzz.java:9: Variable a may not have been initialized.
System.out.println(a.i);
^
1 error
‘a’ was made global so
it does not have to be initialized. a.i displays 9, which means that there is
one and only one i. We repeat, static variables can be accessed without
creating the object.
Here’s another example
to prove the same point
zzz.java
import java.applet.*;
public class zzz extends Applet
{
xxx a,b;
public void init()
{
System.out.println(a.i);
b.i = 20;
System.out.println(a.i);
}
}
class xxx
{
public static int i = 9;
}
C:\javaprg>appletviewer a.html
9
20
At first a.i will
print 9. Then b.i is initialized to 20. b.i and a.i are the same because i is a
static variable and is shared. So when you say a.i again, the value of i is 20.
As you can see, you don’t have to create an object to use static variables.
The next program
introduces the concept of a static function that returns void.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
xxx a;
public void init()
{
a.abc();
}
}
class xxx
{
public static void abc()
{
System.out.println(“hi”);
}
}
Here a.abc calls the
function abc in the class xxx. Once the function is called ‘hi’ is printed on the screen.
c:\javaprg>appletviewer a.html
hi
The need for static
functions will be discussed a little later in this chapter.
In the following
program, the static variable ‘i’ is declared to be private.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
xxx a,b;
public void init()
{
System.out.println(a.i);
b.i = 20;
System.out.println(a.i);
}
}
class xxx
{
private static int i=10;
}
C:\javaprg>javac zzz.java
zzz.java:7: Variable i in class xxx not accessible from class zzz.
System.out.println(a.i);
^
zzz.java:8: Variable i in class xxx not accessible from class zzz.
b.i = 20;
^
zzz.java:9: Variable i in class xxx not accessible from class zzz.
System.out.println(a.i);
^
3 errors
The default is
private, which means that only the class members can access the variable.
“Outsiders are not allowed!” i.e. anyone outside the class is not allowed to
access it. Try to trespass and you will definitely see the watchdog, the error.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
xxx a;
public void init()
{
a=new xxx();
}
}
class xxx
{
private static int i=10;
xxx()
{
i++;
System.out.println(“In Const “+i);
}
}
C:\javaprg>appletviewer a.html
In Const 11
Here xxx increments
the value of i by saying i++ and display its value. Only the constructors and
functions in xxx have access to i. The variables ‘a’ and ‘b’, though created in
zzz and in the very same file, are not allowed to access i.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
}
class xxx
{
public void abc()
{
}
}
class yyy extends xxx
{
public void abc()
{
}
}
In the above program,
apart from zzz there are two more classes, xxx and yyy. Class xxx has a
function called abc. Class yyy extends xxx and also has a function named abc.
This will not result in any compilation errors.
The next program
introduces a small change. Here the word ‘final’ precedes void abc().
zzz.java
import java.applet.*;
public class zzz extends Applet
{
}
class xxx
{
public final void abc()
{
}
}
class yyy extends xxx
{
public void abc()
{
}
}
C:\javaprg>javac zzz.java
zzz.java:13: The method void abc() declared in class yyy cannot override the final method of the same signature declared in class xxx. Final methods cannot be overridden.
public void abc()
^
1 error
Final methods cannot
be changed or overrriden. Since abc has been made final, the class yyy cannot
have another function abc. The abc in xxx is final, thus you can’t change it.
It is not without
purpose that such a concept has been introduced in Java. Let’s understand the
rationale behind it.
Let us assume that you
have your own class with a final function. Others will derive from it, but if
they want to override the same function, they will not be allowed to do so.
They will get the error shown above. Without the use of final there is no
guarantee that the function will not be overridden. Thus to prevent the
overriding of a function, it must be made final.
Now, in xxx, we are
creating a function named abc.
zzz.java
import java.applet.*;
public class zzz extends Applet
{
}
class xxx
{
public void abc() throws IOException
{
}
}
C:\javaprg>javac zzz.java
zzz.java:7: Class IOException not found in throws.
public void abc() throws IOException
^
1 error
The function abc
throws an exception, or to be more specific, it throws IOException. The full
name is java.io.IOException, hence we need to import java.io.*
zzz.java
import java.applet.*;
import java.io.*;
public class zzz extends Applet
{
public void init()
{
try
{
xxx x = new xxx();
x.abc();
}
catch (Exception e){System.out.println(e.getMessage());}
}
}
class xxx
{
public void abc() throws IOException
{
throw new IOException(“hi”);
}
}
C:\javaprg>appletviewer a.html
hi
A function takes
parameters and along with it, it can also throw exceptions. This tells us more
about the function.
This program has x
that looks like xxx and is created on the same line by saying new xxx(). This
does not give us any problems at all. The next line has x.abc(), where we call
this function. abc returns a void and throws an IOException. Within the curly
braces, the command ‘throw’ is used to actually throw the exception. Here, it
throws the predefined exception, which is IOException. Before the exception is
thrown, it must be created. It is created with the help of ‘new’. We are
calling the constructor, which takes one parameter, in this class. A couple of
lines later we will show you how to create your own exceptions.
Every exception thrown
must be caught, so catch catches Exception, which is the base class for all
exceptions. System.out.println prints the return value of e.getMessage. e looks
like Exception and the getMessage function in e displays “hi”. “hi” is
displayed because this is what was given in the constructor. You can have as
many catches as you want for the different exceptions you want to catch.
zzz.java
import java.applet.*;
import java.io.*;
public class zzz extends Applet
{
public void init()
{
try
{
xxx x = new xxx();
x.abc();
}
catch (IOException e){System.out.println(“In IOException “+e.getMessage());}
catch (Exception e){System.out.println(“In Exception “ + e.getMessage());}
finally
{
System.out.println(“All over”);
}
}
}
class xxx
{
public void abc() throws IOException
{
throw new IOException(“hi”);
}
}
C:\javaprg>appletviewer a.html
In IOException hi
All over
Here’s one more
example where we catch IOException and then Exception e. Since abc throws an
IOException, the IOException will be called and not the second one. Once the
first catch is executed, the execution of the other catches stops.
Reversing the catch
order will generate an error.
C:\javaprg>javac zzz.java
zzz.java:13: catch not reached.
catch (IOException e){System.out.println(“In IOException “+e.getMessage());}
^
1 error
In the try and catch,
we have introduced a new word ‘finally’. The code in the curly braces, which
has been given after the word ‘finally’ is called when everything is over.
Hence you see ‘All over’. ‘finally’ gets called irrespective of the throws. To
check this, comment out the throw and you will still see ‘All over’.
‘finally’ is used to
execute code at the end of ‘try’ and ‘catch’ pair. It can be used to close a
file that was opened in the program. The file will be closed irrespective of
whether the exception takes place or not.
Ready for something
interesting? We are now going to show you how to create your own exception.
zzz.java
import java.applet.*;
import java.io.*;
public class zzz extends Applet
{
public void init()
{
try
{
xxx x = new xxx();
x.abc();
}
catch (Exception e){System.out.println(e.getMessage());}
}
}
class xxx
{
public void abc() throws ppp
{
throw new ppp(“hi”);
}
}
class ppp extends Exception
{
ppp(String p)
{
System.out.println(“In const “ + p);
}
}
C:\javaprg>appletviewer a.html
In const hi
null
Here we are calling
our exception ppp which extends Exception, the base class of all exceptions.
Then we create a constructor, which accepts one parameter ‘p’. This value is
displayed using System.out.println. There you go! Exception created.
When we say x.abc, at
first abc in xxx gets called and it immediately throws an exception. This will
call the constructor in ppp. The p in the constructor has the value ‘hi’, hence
we see ‘In const hi’. But e.getMessage does not return any value, so we see
null. Since we do not have the getMessage function, the one in Exception is
called and it returns a null.
In our next program,
we have added the getMessage function in ppp and the statement returned is
“Sonal”.
zzz.java
import java.applet.*;
import java.io.*;
public class zzz extends Applet
{
public void init()
{
try
{
xxx x = new xxx();
x.abc();
}
catch (Exception e){System.out.println(e.getMessage());}
}
}
class xxx
{
public void abc() throws ppp
{
throw new ppp(“hi”);
}
}
class ppp extends Exception
{
ppp(String p)
{
System.out.println(“In const “ + p);
}
public String getMessage()
{
return “Sonal”;
}
}
C:\javaprg>appletviewer a.html
In const hi
Sonal
To print the value
returned by e.getMessage, our getMessage will be called and thus you see
‘Sonal’.
This is not the
correct way to go about doing things, so we now set it in the right way.
When we create an
object, our constructor is given ‘hi’ as a parameter. This constructor should
call the original constructor and give it the same string. Then, the getMessage
function in our code should receive the value returned by the original
function, which will be the value to be returned back.
The next program
implements these two things.
zzz.java
import java.applet.*;
import java.io.*;
public class zzz extends Applet
{
public void init()
{
try
{
xxx x = new xxx();
x.abc();
}
catch (Exception e){System.out.println(e.getMessage());}
}
}
class xxx
{
public void abc() throws ppp
{
throw new ppp(“hi”);
}
}
class ppp extends Exception
{
ppp(String p)
{
super(p);
System.out.println(“In const “ + p);
}
public String getMessage()
{
String s;
s = super.getMessage();
return s;
}
}
C:\javaprg>appletviewer a.html
In const hi
hi
In ppp, we have
super(p) which must be written on the very first line. It is used to call code
in the original. By original we mean the class that we have derived from. In
our case, the constructor in Exception will be called with one parameter p.
This constructor stores the string. In getMessage, we again have super.getMessage.
super.getMessage will call getMessage from the base class, which is Exception.
The getMessage returns a string, which is stored in the variable s and then we
simply return s. Now the program will work in the required manner.
Our next example is
slightly larger.
zzz.java
import java.applet.*;
import java.io.*;
public class zzz extends Applet
{
public void init()
{
try
{
xxx x = new xxx();
x.abc();
}
catch (Exception e){System.out.println(e.getMessage());}
finally
{
System.out.println(“All over”);
}
}
}
class xxx
{
public void abc() throws ppp
{
throw new ppp(“hi”);
}
}
class ppp extends Error
{
ppp(String p)
{
super(p);
System.out.println(“In const “ + p);
}
public String getMessage()
{
String s;
s = super.getMessage();
System.out.println(“In getmessage “+s );
return s;
}
}
C:\javaprg>appletviewer a.html
In const hi
All over
In getmessage hi
In getmessage hi
In getmessage hi
ppp: hi
at xxx.abc(zzz.java:23)
at zzz.init(zzz.java:10)
at sun.applet.AppletPanel.run(AppletPanel.java:333)
at java.lang.Thread.run(Thread.java:479)
Class zzz has a
variable x as an object that looks like xxx. The statement, x.abc, calls the
function abc which throws an exception called ppp. The constructor gets called,
hence ‘In const hi’ is displayed. This is the first line of output. Then
‘finally’ gets called because of which ‘All over’ is displayed. The catch code
will be the next to be called and because we have System.out.println, it will
constantly print e.getMessage, which contains ‘hi’. Once all this is over, it
will tell you that there was an error int xxx.abc at zzz.init.
The reason why all
this happens is that we are not deriving ppp from Exception but instead we are
deriving from Error. The error messages are to be read in the reverse order:
The error is in xxx.abc, which has been called from zzz.init and
AppletPanel.run calls init and so on.
Building Applications
So far you have been
building Applets, now let’s build Applications.
Applets and
applications are very similar in appearance, with one key difference: A Java
application is an independent piece of software; an applet is not. The applet
is loaded and run by a browser or viewer. In fact, the HotJava browser is just
a Java application.
qqq.java
public class qqq
{
}
Start by saying public
class qqq { }. Here, no import statements are used. When you run the program by
saying javac, you get a file named qqq.class and no errors. To see the
application work, instead of appletviewer, run another program called java.
C:\javaprg>java qqq
Exception in thread “main” java.lang.NoSuchMethodError: main
This program gives an
error saying that you don’t have a function called main.
At times, you may get
a different error that looks like the statement given below
Exception in thread “main” java.lang.NoClassDefFoundError: qqq
Then you must set the
classpath to the current directory. In order to do so give the command
>set CLASSPATH=.;%CLASSPATH%
So far we have been
using Java as a programming language. We have written code that executes in a browser. Whenever code runs in a browser,
it is called an applet. This time we want our code to run as a standalone
application. To do so, we require a program called Java, also known as the Java
Virtual Machine. We will go in depth into the differences between an applet and
an application just a little later. As of now, it is important to understand
that a Java applet can’t read and write to a file on disk, whereas a Java
application can do anything that any executable can do.
In the next program,
we have added a function named main.
qqq.java
public class qqq
{
public static void main(String a[])
{
System.out.println(“Hi “);
}
}
Earlier, in this
chapter, we discussed static variables and static functions where we explained
that we don’t have to create an object to access them. main here is a function
and it takes an array of strings named a. You may choose to name the array as
you please. main has been declared public, otherwise, it won’t be visible. main
has also been made static so that it is available to Java without creating the
object that looks like qqq. Static functions are always available irrespective
of you using new or not. main returns void because it is not returning anything
here. The order is important, you cannot mess with it. First you must say
public or private, then static and then give the return value. Compile it and
then say java qqq. It will display ‘hi’.
C:\javaprg>java qqq
hi
Now let’s print out
a[0] and a[1].
qqq.java
public class qqq
{
public static void main(String a[])
{
System.out.println(a[0]);
System.out.println(a[1]);
}
}
Run the compiler and
then say java qqq. It will give an error saying,
ArrayIndexOutOfBoundsException.
C:\javaprg>java qqq
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 0
at qqq.main(qqq.java:5)
Say java qqq one at
the command prompt, this will first show one on the screen and then give the
same error.
C:\javaprg>java qqq one
one
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 1
at qqq.main(qqq.java:6)
To eliminate the
error, say java qqq one two.
C:\javaprg>java qqq one two
one
two
Simply saying java qqq
does not create an array of strings because no parameters have been given after
qqq. java qqq one will create only one element in the array because only one
argument is specified. Hence printing the second member will give an error
because the array is limited to only one member. The last command that you
tried, java qqq one two, creates two elements and since you are displaying two
members you see no errors. Elements in the array are created with respect to
the parameters specified. What we are trying to say here is that if you go
beyond the bounds of the array, an exception will be generated.
The next program is a
generic one, which displays all the command line arguments without showing any
errors.
qqq.java
public class qqq
{
public static void main(String a[])
{
int i;
for ( i = 0 ; i < a.length ; i++)
System.out.println(a[i]);
}
}
C:\javaprg>java qqq one
one
C:\javaprg>java qqq one two three
one
two
three
In Java, an array
class has a member called length. If you say java qqq one, a.length will be 1
because there is only one member. java qqq one two three will make a.length 3
as there are three members. Since the condition is i< a.length, the value of
i will start from 0 and keep changing till it is less than 3 i.e. 2.
System.out.println will therefore print a[0] ,a[1], a[2]. This is how,
depending on the parameters passed, all the members of the array can be
displayed.
Now, let’s try
writting data to the disk.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
}
catch (Exception e){e.getMessage();}
}
}
In this program, fos
is an object that looks like FileOutputStream. We know how much shortcuts are
appreciated, so to avoid writing the full name the import statement has been
used. To create a new instance FileOutputStream requires one parameter, the
name of the file. Our subdirectory is c:\javaprg and the file name we want to
use is z.ser. Similarly, make sure you give the complete path to the
constructor. fos is now an object that looks like FileOutputStream. The name
FileOutputStream itself suggests that the file will be in output mode, i.e. we
can write to the file. Stop here, compile the file and run it. You will find
that z.ser is created in the subdirectory but it’s size is 0 bytes.
Now to write to this
file.
To do that, another
object is needed that looks like ObjectOutputStream. This class takes the
FileOutputStream variable as a parameter and so we pass fos to it. It is closed
on the next line.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.close();
}
catch (Exception e){e.getMessage();}
}
}
Compile this program
and run it. A directory listing in the javaprg subdirectory will display the
file size as 4 bytes.
The bytes are shown in
dec, char and hex below.
172 ¬ ac
237 í ed
0 0
5 - 5
Now we will actually
write to this file.You may wish to write strings and many more things to the
file. oos is used to write to fos, fos stands for z.ser. In the program below,
we are simply writing AB.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(“AB”);
oos.close();
}
catch (Exception e){e.getMessage();}
}
}
Check the size of the
file. It is a very small file and the size is 9 bytes. You can also see 2,
which is the length of the string and then AB.
172 ¬ ac
237 í ed
0 0
5 - 5
116 t 74
0 0
2 2
65 A 41
66 B 42
In the program below,
we are writing two strings to the file. One string is AB and the other is CDE.
The output is shown below.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(“AB”);
oos.writeObject(“CDE”);
oos.close();
}
catch (Exception e){e.getMessage();}
}
}
You will notice that
the string always starts with 116, followed by 0. After that, we have the
length of the string and then the string itself.
172 ¬ ac
237 í ed
0 0
5 - 5
116 t 74
0 0
2 2
65 A 41
66 B 42
116 t 74
0 0
3 3
67 C 43
68 D 44
69 E 45
You can’t be satisfied
with just this, can you? So let’s write an entire object to a file in one
stroke.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
xxx x;
x = new xxx();
try
{
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(x);
oos.close();
}
catch (Exception e){e.getMessage();}
}
}
class xxx implements Serializable
{
public int i=6;
String s = “hi”;
}
In the above program,
x is an object that looks like xxx. It has two members - int i and String s.
writeObject with x will write the entire object to the file.
Class xxx implements
Serializable. This is an interface but it does not have any functions. So,it is
assumed that it only has variables. ObjectOutputStream is used to take the
entire object and write it to disk in one stroke.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
xxx x;
FileInputStream fos = new FileInputStream(“c:\\javaprg\\z.ser”);
ObjectInputStream oos = new ObjectInputStream(fos);
x = ( xxx ) oos.readObject();
System.out.println(x.i);
System.out.println(x.s);
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
class xxx implements Serializable
{
public int i=60;
String s = “Byes”;
}
Instead of
FileOutputStream and ObjectOutputStream, the above program uses FileInputStream
and ObjectInputStream. In the previous example, we had writeObject and here we
have readObject. We have to cast it to xxx. Now when you print x.i and x.n, the
value will be that of the earlier program, it doesn’t take the new values.
C:\javaprg>java qqq
6
hi
Let’s see how arrays
can be saved to the disk.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
String a[];
a = new String[2];
a[0] = “hi”;
a[1] = “Nono”;
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(a);
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
The concept of arrays
has already been explained. Here ‘a’, an array of strings, is created. a[0] is
initialized to ‘hi’ and a[1] to ‘Nono’. Using writeObject, the entire array is
written to disk. ‘a’ has the length of the array so it knows how much to write.
Thinking of taking a
break? Great idea! But please do so after trying out the next program. The next
program will read from the same file into an array. So you need to try this
right now.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
String a[];
FileInputStream fos = new FileInputStream(“c:\\javaprg\\z.ser”);
ObjectInputStream oos = new ObjectInputStream(fos);
a = (String [] ) oos.readObject();
System.out.println(a[0]);
System.out.println(a[1]);
System.out.println(a.length);
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
C:\javaprg>java qqq
hi
Nono
2
First run the earlier
program where you wrote the array to the disk and then the current one. In this
program, readobject will read from the file. Whatever is read in is assigned to
a. Since we have cast the output to an array of strings, ‘a’ now contains the
data as Strings. Therefore, it displays ‘hi’ and ‘Nono’ and the length is displayed
as 2.
Multi-Dimensional Arrays
Let’s understand
multidimensional arrays. In Java, there is no such thing as a multidimensional
array. Arrays are limited to one dimension. But what if you need more complex
data structures such as two or three dimensions? For this you can fake
multidimensional structures by building arrays within arrays.
qqq.java
public class qqq
{
public static void main(String argv[])
{
String a[][] = {{ “a1”,”a2",”a3"} , { “b1”,”b2",”b3"} };
int i;
for ( i = 0 ; i<a.length ; i++)
{
System.out.println(a[i][0]);
}
}
}
C:\javaprg>java qqq
a1
b1
In order to create
multidimensional arrays use two square brackets. In this program, the
multidimensional array is of strings, so it is declared as string a [ ] [ ]. At
the same time, the array is also being initialized using curly braces. Since
there are two sets of curly brackets, we can say that we have an array
a[2],[3]. Each one of them is an array and each one has 3 members.
The for loop starts by
initializing i to 0. a.length will give you 2 because the array only has two
members, each one of them in turn is an array, so their length should be three.
When we say println a[i][0], it is a[0][0]. This will print the first member of
the first array, that is, a1. When i becomes 1 we are printing a[1][0] and this
will print b1.
The next program
enables you to print all the members in the array.
qqq.java
public class qqq
{
public static void main(String argv[])
{
String a[][] = {{ “a1”,”a2",”a3"} , { “b1”,”b2",”b3"} };
int i,j;
for ( i = 0 ; i<a.length ; i++)
{
System.out.println(a[i][0]);
for ( j = 0 ; j < a[i].length ; j++)
{
System.out.println(a[i][j]);
}
}
}
}
C:\javaprg>java qqq
a1
a1
a2
a3
b1
b1
b2
b3
The objective here is
to print all the members in the array. i in the for loop is initialized to 0;
the condition is i<a.length. a.length will give 2. So the println will print
the value in a[0][0], which is a1. Then we have another for loop within the
earlier for. j in the loop gets initialized to 0; the condition is j <
a[i].length. The length here will be 3 because the first array has 3 members.
Remember, a[0] and a[1] are both arrays. So j will be 0,1,2 and thus will print
all members of the array.
The same is applicable
to ints also. The following program demonstrates this.
qqq.java
public class qqq
{
public static void main(String argv[])
{
int [][] m;
m = new int[3][];
int i;int k = 1;
for ( i = 0 ; i < m.length ; i++)
{
m[i] = new int[2];
m[i][0] = k++;
m[i][1] = k++;
}
for ( i = 0; i < m.length ; i++)
{
System.out.println(m[i][0]);
System.out.println(m[i][1]);
System.out.println(“—”);
}
}
}
C:\javaprg>java qqq
1
2
—
3
4
—
5
6
—
Here, the variable has
been created in a slightly different manner. You can create it either by saying
int m[ ] [ ] or int [ ][ ]m. The square brackets can be put before or after the
variable, it’s just a question of syntax. They both mean the same thing. m=new
int[3][ ] will create 3 arrays but how many members each of them will hold is
not known. It has been left blank for the moment. Then we have a for statement
where m.length will be 3 because there are 3 arrays, so the for will go on
three times.
In the for, we say
m[i] = new int[2]. This is how we initialize these arrays. Since i is 0, the
0th member of the array will hold two values. m[i][0] is actually m[0][0],
which we are initializing to the value of k. k as of now is 0 which is the
value given to m[0][0]. k++ will increment the value by 1, so k becomes 1. This
is given to m[0][1]. When the bracket is reached, i will be incremented by 1,
so it becomes 1. m[1] is now an array which will have 2 elements. And m[i][0]
is now m[1][0] which refers to the second array and the 0 th element in the
array. Since k has not been initialized again, k will retain its original value
and will keep incrementing.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
String a[][] = {
{ “a1”,”a2",”a3" },{ “b1”,”b2",”b3" }};
//a = new String[3][2];
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(a);
oos.close();
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
In this program, the
multidimensional array has 2 arrays each with 3 members. It could have been
created as shown in the comment and we could have initialized every member
later. It really doesn’t make any difference. With writeObject, the entire
object will be written to disk.
The next program reads from the file and prints
it in the form of an array.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
String a[][];int i,j;
FileInputStream fos = new FileInputStream(“c:\\javaprg\\z.ser”);
ObjectInputStream oos = new ObjectInputStream(fos);
a = (String [][] ) oos.readObject();
System.out.println(a.length);
for ( i = 0 ; i < a.length ; i++)
{
for ( j = 0 ; j < a[i].length ; j++)
System.out.println(a[i][j]);
}
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
C:\javaprg>java qqq
2
a1
a2
a3
b1
b2
b3
Here, we want to read
all the strings, so we read the object into a. The for statement initializes i
to 0 and it keeps incrementing i till it is less than the length, which is 2.
This for will go on twice, the second for is the one that prints a1, a2, a3 in
the first round and b1, b2, b3 in the second round.
See how easy it is to
write and read an array of strings. Let’s see if we can work with chars as
comfortably.
The difference between
an array of chars and an array of strings is that a char holds a single entity
whereas a string holds multiple entities.
The following program
has a multidimensional array with 2 arrays each 3 members large. The values
given are ‘a’ ‘b’ ‘c’ ‘d’ ‘e’ ‘f’.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
char a[][] = {
{ ‘a’,’b’,’c’ },{ ‘d’,’e’,’f’ }};
FileOutputStream fos = new FileOutputStream(“c:\\javaprg\\z.ser”);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(a);
oos.close();
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
As previously, we are
writing the object in one stroke to the file and in a similar way we are
reading it from the file.
qqq.java
import java.io.*;
public class qqq
{
public static void main(String argv[])
{
try
{
char a[][];
FileInputStream fos = new FileInputStream(“c:\\javaprg\\z.ser”);
ObjectInputStream oos = new ObjectInputStream(fos);
a = (char [][] ) oos.readObject();
System.out.println(a[0]);
System.out.println(a[0][0]);
System.out.println(a[1]);
}
catch (Exception e){System.out.println(“bye”);e.getMessage();}
}
}
C:\javaprg>java qqq
abc
a
def
a[0] within the
println prints all the characters in one stroke. To print individual characters
we have to be specific, like a[0][0] is ‘a’ and so on. a[0] will print the
entire string ‘abc’ and a[1] will print out the entire string ‘def’.
Thus the crux is that
using ObjectInputStream and ObjectOutputStream you can read and write arrays to
the disk.
Conclusion
In this chapter, you
learnt about static variables and static functions and gained some insight into
the concept of constructors.We also showed you how you can create your own
exceptions.
Apart from the applets
that you have been creating, you are now able to create applications. Using ObjectInputStream and
ObjectOutputStream you can read and write arrays to the disk. After readig this
hapter, we hope you are now well versed with the concept of multidimensional
arrays in connection with objects and classes.