Link to home
Start Free TrialLog in
Avatar of calvinrsmith
calvinrsmith

asked on

need help to initilize class

here is my current code:
class Info
{
   public String name;
   public String[] friends;
   public String[] kids;
   public String secretword;
};

and here is my attempt to initilize it:
Info I[] = {
   {"fred", {"bob",sam"}, {"joey"}, "tree"},
   { "ben", null, {"daryl", "eric", "frank" }, "mountain"}
          };

when I compile this:
Invalid initializer for type Info


What is the proper way to do this?
ASKER CERTIFIED SOLUTION
Avatar of Jod
Jod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of calvinrsmith
calvinrsmith

ASKER

Thanks, for your comment.  The current situation doesn't look possible (as you said) Perhaps there is another way?  
I need to have the Info array initilized so that it can be used as a static member.  This must happen before the first time the class that uses it is ever called.  I thought about just setting the variable to null and checking for null in the constructor but this idea breaks down if a thread creats an instance of the class before the other one is through setting it up.  I could lock the variable during initilization, but having it setup like i'm trying would be ideal.
You need to do your initialisation in something called a constructor.

to run the above code save it into a file called

  test.java

compile it, using

javac test.java

or use whatever tool you are compiling your java with and then run it as an application:

  java test

You will see the following output:

      fred
      bob
      sam
      joey
      tree

So, what are constructors and how do they work? Well the explanation is as follows...(from Thinking in Java with a few adjustments to ease explanation)

*********************
How do you initialise your objects?

You can imagine creating a method called initialize( ) for every class you write. The name is a hint that it should be called before using the object. Unfortunately, this means the user must remember to call the method. In Java, the class designer can guarantee initialization of every object by providing a special method called a constructor.

If a class has a constructor, Java automatically calls that constructor when an object is created, before users can even get their hands on it. So initialization is guaranteed.

The next challenge is what to name this method. There are two issues. The first is that any name you use could clash with a name you might like to use as a member in the class. The second is that because the compiler is responsible for calling the constructor, it must always know which method to call. The C++ solution seems the easiest and most logical, so it’s also used in Java: The name of the constructor is the same as the name of the class.

It makes sense that such a method will be called automatically on initialization.

Here’s a simple class with a constructor:

//: SimpleConstructor.java
// Demonstration of a simple constructor

      class Rock {
        Rock() { // This is the constructor
          System.out.println("Creating Rock");
        }
      }

      public class SimpleConstructor {
        public static void main(String[] args) {
          
            // create 10 rock objects...
          for(int i = 0; i < 10; i++) {
              new Rock();
            }

        }
      }

Now, when an object is created:

new Rock();

storage is allocated and the constructor is called. It is guaranteed that the object will be properly initialized before you can get your hands on it."


What I have done for your code, is taken this idea one step further - rather than use a default constructor, I have created one that takes parametrs and these parametrs are the data that you want to place in the variables inside the info object.


The next thing is how to pass your variables in.

The part of the code that does this is here:

 
    String[] temp1 = {"bob","sam"};
    String[] temp2 = {"joey"};

    // this line creates and initialises your object
    info i = new info("fred", temp1, temp2, "tree");


In Java you need to use the syntax to create objects:

  MyObject m = new MyObject();

This tells the compiler that you wish to have a new variable MyObject and make it the same as the value of 'new MyObject()'.

By now you should be able to see that 'new MyObject()' firstly allocates space for a new MyObject in the computers memeory and then calls the default Constructor of MyObject to initalize this object.

What this line is doing:

    info i = new info("fred", temp1, temp2, "tree");

is to allocate space for an info object and then initialise it with the parameters that are passed into it.

This in turn then calls the method:

  public info (String n, String[] f, String[] k, String s) {
    name = n;
    secretword = s;
    friends = f;
    kids = k;
  }
     
which as you can see accepts these parameters and stores them in the variables you have set aside for this data.

The reason you have to use temp1 and temp2 is that you cannot do this:

    info i = new info("fred", {"bob","sam"}, {"joey"}, "tree");

because you will get this error:

  Array constants can only be used in initializers

'initializers' in this case refers to statements like:

    String[] temp1 = {"bob","sam"};
    String[] temp2 = {"joey"};

You could do this:

    info i = new info("fred", new String[]{"bob","sam"}, new String[]{"joey"}, "tree");  

but it is just easier to read the way I have done it.


Now you can see that inside your new object i you have the following data

    System.out.println(i.name);
    System.out.println(i.friends[0]);
    System.out.println(i.friends[1]);
    System.out.println(i.kids[0]);
    System.out.println(i.secretword);  

which will print out as

fred
bob
sam
joey
tree

Finally if you wanted to create an array of info objects you can do it like this:

  // create an array of 2 info objects
  info[] iArray = new info[2];

  // setup and create first element of array
  String[] temp1 = {"bob","sam"};
  String[] temp2 = {"joey"};  
  iArray[0] = new info("fred", temp1, temp2, "tree");

  // setup and create second element of array
  String[] temp1 = new String[0];  
  String[] temp2 = {"daryl", "eric", "frank" };  
  iArray[0] = new info("ben", temp1, temp2, "mountain");

This line makes your null array:

  String[] temp1 = new String[0];

but your program will complain if you try and access this array now as you have not put any data in it, therefore it has no elements so even:

  temp1[0]

will fail.

Is this clearer now? Quite a lot to take in I know, but I figured you need a proper explanation of how this is supposed to work.
You probably don't need that much of the above explanation then...ho hum...
One way of doing this is a static code block. This will run whenever the class is loaded but before any instances are created. However, all static data is only one per class and not one per instance so you can only have this static code block run once the very first time the class is loaded.

The details it then sets in the static variables are then set for good.

Generally, anything static in a class cannot internally refer to anything to do with an instance of a class when it is created.

What is it you are trying to achieve?

If the data you want to put in info has to be different for each instance of info then static code will not work in it's most basic form.

I would need to know what it is you are trying to achieve to suggest a workaround but there are various workarounds.

Why can't you just hardcode the data into variables to start with as constants? Do they need to be changeable at runtime at all or are they set up as you are doing above as static initialisation strings at compile time.
I'm creating a code generator and I would like to use info to store information about the code format.  

This information never changes at run-time since the code format will always be the same.  

Your idea about a static function to initilize info sounds good since info is static (and constant) anyway.

I scanned 'thinking in java' but didn't find this mentioned, but might have missed it.

If the info is static the nyou can do this.

What you need to do is create a class that is like a 'reference' object. It will contain various data that are constants.

To do this with the above data, you can do it like this:

public class info {
     
  public static final String name = "fred";
  public static final String[] friends = new String[] {"bob","sam"};
  public static final String[] kids = new String[] {"joey"};
  public static final String secretword = "tree";
}

You can now refer to this data as:

myName = info.name;
oneFriend = info.friends[0]; // first friend in String array friends

and so on. You do not need to initialise the class or create an instance - you can just refer to the variables directly like this in your code.

In general,

static - makes a variable available outside of the instance of a class

final - makes a variable a constant so it cannot be changed by accident at runtime.

There are various details about Static variables in Thinking in Java. A brief overview is given in this chapter (this is the on line verion of thinking in Java...)

http://codeguru.developer.com/java/tij/tij0037.shtml#Heading79
Now remember how in my original code I need an array of info objects.  The entire array is static and will never change.  Your example is good for element 0, but how do I add the data for the other elements?
One simple way to set up the data is like this:

public class info {

  // these constants make it easier to find the data
  public static final int FRED = 0;
  public static final int BOB = 1;
  public static final int SARAH = 2;

  public static final String[] name = new String[]
                        {
                          "fred", //element 0
                          "bob",  //element 1
                          "sarah" // element 2            
                        };
                       
  public static final String[][] friends = new String[][]
                        {
                          {"bob","sam"},
                          {"jim","tony"},
                          {"sandra"}
                        };
                       
  public static final String[][] kids = new String[][]
                        {
                          {"kid1","kid2"},
                          {"kid1"},
                          {"kid1", "kid2", "kid3"}
                        };
  public static final String[] secretword = new String[]
                        {
                          "tree", //element 0
                          "free",  //element 1
                          "glee" // element 2            
                        };

  ////////////
  // TEST CODE
  ////////////
  public static void main (String[] args) {
   

    //Now see what we have created by looping through all the details
    // we see how many names there are and use this to identify the
    // number of times to go round the loop
    for (int i = 0; i < info.name.length; i++) {

      System.out.println( "\nDetails for " + info.name[i] + ":" );
      System.out.println( "   Secret word is " + info.secretword[i] );

      for (int j = 0; j < info.friends[i].length; j ++) {
        System.out.println( "   Friends " + i + " is called " + info.friends[i][j] );
      }

      for (int j = 0; j < info.kids[i].length; j ++) {
        System.out.println( "   Child " + i + " is called " + info.kids[i][j] );
      }
    }


    // Also we can print out the details of each
    //  name by using the constants for example...
    System.out.println("\n\n Print name using constant identifier: " + info.name[info.FRED] );

  }
}

which will ouput the following details...


Details for fred:
   Secret word is tree
   Friends 0 is called bob
   Friends 0 is called sam
   Child 0 is called kid1
   Child 0 is called kid2

Details for bob:
   Secret word is free
   Friends 1 is called jim
   Friends 1 is called tony
   Child 1 is called kid1

Details for sarah:
   Secret word is glee
   Friends 2 is called sandra
   Child 2 is called kid1
   Child 2 is called kid2
   Child 2 is called kid3


 Print name using constant identifier: fred

You could also put the data into more advanced objects such as a Vector, List or HashTable but as you can see the above will work just fine.

Also, if you set up a constant for each name, such as:

  public static final int FRED = 0;

when you are looking for a particular item of data for Fred, you can index into the arrays very quickly and retrieve data at the fastest possible speed.

OK?
I was afraid of that...
I was never able to do what I was trying to do, but using your ideas I was able to get a working solution.  Thanks.