Hello there,


I am working on an assignment for school and I am having a hard time understanding the concept of an array of objects. I am required to create an array of Music objects so that I can search through them via a binary search and make changes as stipulated by reading a .txt file.

My problem is, I do not think I understand Object arrays properly. I can not seem to populate the array from the Music class. Do I populate in the instanceOf if block? Does it matter? I have two test populations of the array under the music instance of RockSong block and on trying to System.out.println() the output for accuracy I just get a null result. Any shove in the right direction would be most appreciated. Thank you.

public class Main
{
    private TextFileReader listenFile;
    private ListenFile currentRecord, nextRecord;
    private Music music;

    String listenDate = "";
    String listenName = "";
    String musicType ="";
    String rockGroup = "";
    String musicName = "";
    Calendar date;
    Calendar closeDate;
    Date df;

   public static void main (String args[])
   {
    (new Main()).DisplayFile();
   }

   private void DisplayFile()
       {
       int count =0;


     ObjectInputStream inFile = null;
     try
     { inFile = new ObjectInputStream (new FileInputStream("music.dat"));}
     catch (IOException ioex) { System.out.println ("ERROR Opening"); System.exit(1); }

     try
     {
		 while (true)
		 {
			 Music music = (Music)inFile.readObject();
             Music[] musicArray= new Music[300];
             

             if (music instanceof RockSong){

                 musicArray[0].name = music.name;
                 muiscArray[1].timesPlayed = music.timesPlayed;
                         
                      }

             if (music instanceof ClassicalPiece){
          

             }
             if (music instanceof Musical){
                closeDate = (((Musical)music).close);
                  if (closeDate == null) {
                   ((Musical)music).close=Calendar.getInstance();
                 }

             }
              System.out.println(musicArray[count]);

              count++;

           }
	 }
     catch (EOFException eofex) { System.out.println ("\nDONE");}
     catch (IOException ioex) { System.out.println ("ERROR Reading"); System.exit(1); }
     catch (ClassNotFoundException cnfex) { System.out.println ("ERROR class"); System.exit(1); }

   }

And here are my classes:

class Music implements Serializable
{
     String name;
     int timesPlayed;
     Calendar lastTime;
}

class RockSong extends Music
{
     String group;
}

class ClassicalPiece extends Music
{
     String composer;
     String type;
}

class Musical extends Music
{
     Calendar open;
     Calendar close;
}

Hello there,


I am working on an assignment for school and I am having a hard time understanding the concept of an array of objects. I am required to create an array of Music objects so that I can search through them via a binary search and make changes as stipulated by reading a .txt file.

My problem is, I do not think I understand Object arrays properly. I can not seem to populate the array from the Music class. Do I populate in the instanceOf if block? Does it matter? I have two test populations of the array under the music instance of RockSong block and on trying to System.out.println() the output for accuracy I just get a null result. Any shove in the right direction would be most appreciated. Thank you.

public class Main
{
    private TextFileReader listenFile;
    private ListenFile currentRecord, nextRecord;
    private Music music;

    String listenDate = "";
    String listenName = "";
    String musicType ="";
    String rockGroup = "";
    String musicName = "";
    Calendar date;
    Calendar closeDate;
    Date df;

   public static void main (String args[])
   {
    (new Main()).DisplayFile();
   }

   private void DisplayFile()
       {
       int count =0;


     ObjectInputStream inFile = null;
     try
     { inFile = new ObjectInputStream (new FileInputStream("music.dat"));}
     catch (IOException ioex) { System.out.println ("ERROR Opening"); System.exit(1); }

     try
     {
		 while (true)
		 {
			 Music music = (Music)inFile.readObject();
             Music[] musicArray= new Music[300];
             

             if (music instanceof RockSong){

                 musicArray[0].name = music.name;
                 muiscArray[1].timesPlayed = music.timesPlayed;
                         
                      }

             if (music instanceof ClassicalPiece){
          

             }
             if (music instanceof Musical){
                closeDate = (((Musical)music).close);
                  if (closeDate == null) {
                   ((Musical)music).close=Calendar.getInstance();
                 }

             }
              System.out.println(musicArray[count]);

              count++;

           }
	 }
     catch (EOFException eofex) { System.out.println ("\nDONE");}
     catch (IOException ioex) { System.out.println ("ERROR Reading"); System.exit(1); }
     catch (ClassNotFoundException cnfex) { System.out.println ("ERROR class"); System.exit(1); }

   }

And here are my classes:

class Music implements Serializable
{
     String name;
     int timesPlayed;
     Calendar lastTime;
}

class RockSong extends Music
{
     String group;
}

class ClassicalPiece extends Music
{
     String composer;
     String type;
}

class Musical extends Music
{
     Calendar open;
     Calendar close;
}

Ok, so I understand a bit of what I did wrong. I moved the initialization of the musicArray out of the while loop as it was resetting every time it looped. (duh!) This helped me to be able to populate the musicArray to some degre. The problem I am running into now is that when I try to populate the array in the instanceOf block I get a null pointer exception when it hits that instance. For example,

private void DisplayFile()
       {
       int count =0;
      Music[] musicArray= new Music[300];

     ObjectInputStream inFile = null;
     try
     { inFile = new ObjectInputStream (new FileInputStream("music.dat"));
     listenFile = new TextFileReader("listen.txt");}
     catch (IOException ioex) { System.out.println ("ERROR Opening"); System.exit(1); }

     try
     {
		 while (true)
		 {
			 Music music = (Music)inFile.readObject();


             if (music instanceof RockSong){

                      musicArray[count].name = music.name;
                      musicArray[count].timesPlayed = music.timesPlayed;
                       musicArray[count].lastTime = music.lastTime;
                   //What do I put here to call the group object in the RockSong class
                      
                      }

             else if (music instanceof ClassicalPiece){


             }
             else if (music instanceof Musical){
                closeDate = (((Musical)music).close);
                  if (closeDate == null) {
                   ((Musical)music).close=Calendar.getInstance();
                  }

             }

            // musicArray[count] = music;
              System.out.println(count+"  "+music);

              count++;

           }
	 }
     catch (EOFException eofex) { System.out.println ("\nDONE");}
     catch (IOException ioex) { System.out.println ("ERROR Reading"); System.exit(1); }
     catch (ClassNotFoundException cnfex) { System.out.println ("ERROR class"); System.exit(1); }

   }

This code produces a null pointer exception right when it hits the object in the music.dat file that is a RockSong object. I am having trouble finding the correct syntax to put that object into the array. ANy help would be greatly appreciated once again. :)

Even though from your code you have figured out on your own how to use array of objects here is a small example:

Music [] array = new Music[3]; // array is an array and it is not null

// Its elements are so you need to initalize them
array[0] = new RockSong();
array[1] = new ClassicalPiece();
array[2] = new Musical();
// array[0], array[1], array[2] are Music

for (int i=0;i<array.length;i++) {
   if  (array[i] instanceof RockSong){
        RockSong rs = (RockSong)array[i]; // this is how you cast
  } else ...
}

Now as far as the rest of your code:

This is an endless loop because you don't specify when to stop, nor you know the end of the file or how many Music objects are in the file.

while (true)
{
    Music music = (Music)inFile.readObject();

I don't know what will the method do if there are no more objects. Maybe that is why you are getting a NullPointerException. Try to print what you get as soon you read the file and try it with a small file that has only 2 objects

Second, What is the format of the file. I mean how were the objects serialized?


Also here a suggestion depending on your requirements.
Another way for the file to have more than one Music objects then why don't you serialize a Vector:

Vector<Music> v = new Vector<Music>();

v.add(new RockSong());
v.add(new ClassicalPiece());
v.add(new Musical());

// serialize the Vector in the file.

Then when you read the file, the object that the method will return will be of type: Vector<Music> . And with only one call you will have all the Musics inside the Vector.


In order for the above to work all the classes used including their private properties need to implement the Serializable. If you check the API the classes Vector and Calendar already do that. So you are OK. This was just a reminder.

I hope you have checked these:
http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectOutputStream.html
http://java.sun.com/j2se/1.4.2/docs/api/java/io/ObjectInputStream.html

After taking a closer look at the code you don't need the casting. Since you read from the file a Music object, it doesn't matter what type of music it is:

while (true) {
     Music music = (Music)inFile.readObject();
     musicArray[count] = music;
     System.out.println(count+": "+musicArray[count]);
     count++;
}

Also I would suggest to put the EOFException inside the while loop.

while (true) {
     try {

     } catch (EOFException eofe) {
         break;
     }
}

Leave the rest of the exceptions outside. With that way you will exit the loop once you are done reading the file and then you can do whatever you want with the array, without having to end the program.
Then after the while loop through the array and print its elements

Hey there,

I wanted to start by saying thank you so much for responding. I just woke up so I am going to feed the baby and all that good stuff and then get back to the code. I was working on it last night late and I feel like I am getting closer. I really appreciate the help and I am going to take a look at your suggestions and try to implement them. I will reply with my revised code as I do. I did have a question though.
You said I do not need casting but I am having trouble putting the subclass object variables into the musicArray. I read last night that this is because I have to upcast to the parent object. Is this the case? Is there an easier way to do it because of the fact the subclasses are extensions of the superclass?

You said I do not need casting but I am having trouble putting the subclass object variables into the musicArray. I read last night that this is because I have to upcast to the parent object.

I ran this:

Music [] array = new Music[3]; // array is an array and it is not null

        // Its elements are so you need to initalize them
        array[0] = new RockSong();
        array[1] = new ClassicalPiece();
        array[2] = new Music();
        // array[0], array[1], array[2] are Music

        for (int i=0;i<array.length;i++) {
           System.out.println(array[i]);
        }

And it worked.
For the other way around you need "down casting", after checking of course if it can be done with the "instanceof"

Ok....So I have been working on the code and I have actually gotten tot the point where I can view the instance variables of the subclasses without any casting. The problem I face now is, that after adding all the System.out lines so I can check the accuracy of my output I am getting:

Exception in thread "main" java.lang.ClassCastException: ClassicalPiece cannot be cast to Musical

for line 68 which is:

System.out.println(i+" "+musicArray[i].name+" "+musicArray[i].timesPlayed+" "+musicArray[i].lastTime.getTime()+" "+((Musical)musicArray[i]).open.getTime()+((Musical)musicArray[i]).close.getTime());

I am not sure why this is happening. Is it because I have not initialized the elements in the array like you suggested? AM I overlooking something easy and obvious? Here is my updated code.

while (true)
         {


			 Music music = (Music)inFile.readObject();
            
               for(int i=0; i<musicArray.length; i++){
             if (musicArray[i] instanceof RockSong){
               
                  musicArray[i] = music;
                 System.out.println(i+" "+musicArray[i].name+" "+musicArray[i].timesPlayed+" "+musicArray[i].lastTime.getTime()+" "+((RockSong)musicArray[i]).group);

                      }
              if (musicArray[i] instanceof ClassicalPiece){

                musicArray[i] = music;
                System.out.println(i+" "+musicArray[i].name+" "+musicArray[i].timesPlayed+" "+musicArray[i].lastTime.getTime()+" "+((ClassicalPiece)musicArray[i]).composer+" "+((ClassicalPiece)musicArray[i]).type);

             }
              if (musicArray[i] instanceof Musical){
                closeDate = (((Musical)musicArray[i]).close);
                  if (closeDate == null) {
                   ((Musical)musicArray[i]).close=Calendar.getInstance();
                }

                 musicArray[i] = music;
                 System.out.println(i+" "+musicArray[i].name+" "+musicArray[i].timesPlayed+" "+musicArray[i].lastTime.getTime()+" "+((Musical)musicArray[i]).open.getTime()+((Musical)musicArray[i]).close.getTime());

             }
               
             musicArray[i] = music;
}
              count++;

           
             

	 }
     } catch (EOFException eofex) { System.out.println ("\nDONE");}
     catch (IOException ioex) { System.out.println ("ERROR Reading"); System.exit(1); }
     catch (ClassNotFoundException cnfex) { System.out.println ("ERROR class"); System.exit(1); }

I might be off on my implementation. The thing is, if I blank out the two System.out lines in the ClassicalPiece and Musical instanceOf blocks I can get a print linen from the RockSong instanceof. Back to work on it I guess. :)

Hey again,

So after some fiddling with the code I figured it out! Thanks so much for your help, JavaAddict, it really helped me to understand where to go. I really appreciate it. I thought I would post the final code that worked for me and then get moving on the next aspect of the code. If I need any further guidance I will be sure to pop back in. Thanks again. :)

private void DisplayFile()
       {
       int count =0;


     ObjectInputStream inFile = null;
     try
     { inFile = new ObjectInputStream (new FileInputStream("music.dat"));
     listenFile = new TextFileReader("listen.txt");}
     catch (IOException ioex) { System.out.println ("ERROR Opening"); System.exit(1); }

     try
     {

		 while (true)
         {


			 Music music = (Music)inFile.readObject();
            
              // for(int i=0; i<musicArray.length; i++){
             if (music instanceof RockSong){
               
                  musicArray[count] = music;
                 System.out.println(count+" "+musicArray[count].name+" "+musicArray[count].timesPlayed+" "+musicArray[count].lastTime.getTime()+" "+((RockSong)musicArray[count]).group);


                      }
              if (music instanceof ClassicalPiece){

                musicArray[count] = music;
                System.out.println(count+" "+musicArray[count].name+" "+musicArray[count].timesPlayed+" "+musicArray[count].lastTime.getTime()+" "+((ClassicalPiece)musicArray[count]).composer+" "+((ClassicalPiece)musicArray[count]).type);

             }
              if (music instanceof Musical){
                closeDate = (((Musical)music).close);
                  if (closeDate == null) {
                   ((Musical)music).close=Calendar.getInstance();
                }

                 musicArray[count] = music;
                 System.out.println(count+" "+musicArray[count].name+" "+musicArray[count].timesPlayed+" "+musicArray[count].lastTime.getTime()+" "+((Musical)musicArray[count]).open.getTime()+((Musical)musicArray[count]).close.getTime());              
             }

              count++;      

	 }
     } catch (EOFException eofex) { System.out.println ("\nDONE");}
     catch (IOException ioex) { System.out.println ("ERROR Reading"); System.exit(1); }
     catch (ClassNotFoundException cnfex) { System.out.println ("ERROR class"); System.exit(1); }

First of all this: musicArray[count] = music; count++; Can go outside the if statements. I mean in all the ifs you do the same. It doesn't matter what type of Music it is you are still going to put it in the array, so you can have it outside. You repeat the above in all of your ifs. And what will happen if the music is of type Music. You don't have such if statement.


Here is an example on how you can make the code better:

public class Music implements Serializable {
    public [B]Music[/B]() {
    }
    
    public String [B]toString[/B]() {
        return "This class is of type: "+this.getClass().getName();
    }
    
    public void [B]print[/B]() {
        System.out.println("This is a [B]Music[/B].");
    }
}
public class [B]ClassicalPiece [/B]extends Music {
    public ClassicalPiece() {
    }
    
    public void [B]print[/B]() {
        System.out.println("This is a [B]ClassicalPiece[/B].");
    }
}
public class [B]RockSong [/B]extends Music {
    public RockSong() {
    }
    
    public void [B]print[/B]() {
        System.out.println("This is a [B]RockSong[/B].");
    }
}

As you can see they all have the "print" method:

public static void main(String[] args) {
        Music [] array = new Music[3];

        array[0] = new RockSong();
        array[1] = new ClassicalPiece();
        array[2] = new Music();

        // array[i] are Music type.

        for (int i=0;i<array.length;i++) {
            array[i].print();
        }
    }

array are Music type. So you would assume since the print method of the Music class is called this would be the result:

This is a Music.
This is a Music.
This is a Music.

After all, the array is Music and you call the print method. But if you run it you will get:

This is a RockSong.
This is a ClassicalPiece.
This is a Music.

Because even though the array is Music[] some of the elements are RockSong and ClassicalPiece. So even though you do this: Music.print() it is not always the print method of the super class that will be called. The array[0] is a RockSong so the print method of the RockSong will be called.

How is this going to help you?
Your code:

System.out.println(count+" "+musicArray[count].name+" "+musicArray[count].timesPlayed+" "+musicArray[count].lastTime.getTime()+" "+((RockSong)musicArray[count]).group);

System.out.println(count+" "+musicArray[count].name+" "+musicArray[count].timesPlayed+" "+musicArray[count].lastTime.getTime()+" "+((ClassicalPiece)musicArray[count]).composer+" "+((ClassicalPiece)musicArray[count]).type);

System.out.println(count+" "+musicArray[count].name+" "+musicArray[count].timesPlayed+" "+musicArray[count].lastTime.getTime()+" "+((Musical)musicArray[count]).open.getTime()+((Musical)musicArray[count]).close.getTime());

With my code, have each class have a print method that just prints whatever you want. Then:

Music music = (Music)inFile.readObject();

music.print();

musicArray[count] = music;
count++;

It is not the print method of the Music class that will be called but the method of the class that the music instance is. So have the super class have that method and then override it in the other child classes. By implementing it in the super class you make sure that this code will run: music.print(); I mean if you don't put it in the super class the above will not compile since the class will not have such method. Then you put it in the rest of the children so their method will be called, not the super method.

And by implementing it in the super class you fix a bug that you have:

if (music instanceof RockSong){
...
}
if (music instanceof ClassicalPiece){
...
}
if (music instanceof Musical){
...
}

What will happen if the music returned is none of the above and it is just Music. Then nothing will happen, you will not print it and you will not save it in the array.
But by putting the method in the super you make sure always you will print something and put that music in the array

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

As for the toString method that is only declared in the Music class and not in any of the children,try this:

Music [] array = new Music[3];

        array[0] = new RockSong();
        array[1] = new ClassicalPiece();
        array[2] = new Music();

        for (int i=0;i<array.length;i++) {
            // the toString method of the Object class is automatically called
            // Object is the class that all classes extend
            // You override it in the Music
            System.out.println(array[i]); 
        }

You will see that it prints differently depending on the instance. Even though it is declared in only the Music class all it does is return the class name of the instance: this.getClass().getName() But each instance that calls it is different so the super toString method will be called all the time, but return different value with the class name of each caller

This question has already been answered. Start a new discussion instead.