Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / May 2007

Tip: Looking for answers? Try searching our database.

a question related to "final static" field variable

Thread view: 
www - 04 May 2007 19:25 GMT
Hi,

I want to have a static field variable. I want to initiate it once and
don't want it to be changed any more. So

public MyClass
{
    public final static rootDir; //error: saying rootDir may not be
initialized

    public MyClass(String dir)
    {
        rootDir =dir;  //error: saying that I cannot assign to a final variable
    }

    ...

    public void doIt()
    {
        ...
    }

    public static void main(String[] args)
    {
        String str = args[0];
        MyClass class = new MyClass(str);

    }
}

I thought final variable can be assigned value once and only once. And
this can be done inside constructor. Cited from this web page:
http://renaud.waldura.com/doc/java/final-keyword.shtml in Final Field part.

Thank you for your help.
Knute Johnson - 04 May 2007 19:34 GMT
> Hi,
>
[quoted text clipped - 32 lines]
>
> Thank you for your help.

Unfortunately not if it is also static.

Signature

Knute Johnson
email s/nospam/knute/

Sanjay - 04 May 2007 19:46 GMT
> I thought final variable can be assigned value once and only once. And

It is a static variable and has nothing to do with the object of that
class. It get its value when classloader loads the class. What you are
trying to do is, not assigning value to 'rootDir' at all and then are
trying to change it in the contructor,  hence the error.

> this can be done inside constructor. Cited from this web page:
> http://renaud.waldura.com/doc/java/final-keyword.shtml in Final Field
part.

I am not sure what that web page says, but there is a subtle difference
between final and final static variable. May be you want to read this

http://java.sun.com/docs/books/tutorial/java/javaOO/classvars.html
visionset - 04 May 2007 19:50 GMT
> I want to have a static field variable. I want to initiate it once and
> don't want it to be changed any more. So
[quoted text clipped - 10 lines]
>
> Thank you for your help.

The problem is that the rootDir reference may be accessed before the
constructor is called since it is static.
The obvious value for it to hold would be null, so you therefore would not
be able to reasign in your constructor. Because of this the compiler forces
you to assign at the point of declaration.

Signature

Mike W

www - 04 May 2007 20:08 GMT
Thank you all. I have realized I was wrong. But, to achieve my purpose,
do you have any suggestions?

Thank you.
Patricia Shanahan - 04 May 2007 20:16 GMT
> Thank you all. I have realized I was wrong. But, to achieve my purpose,
> do you have any suggestions?
>
> Thank you.

Make rootDir private and change it only once inside the class, from main.

If other classes need access you can provide a getRootDir() method,
which can check for attempts to read it before it has been set.

Patricia
www - 04 May 2007 21:06 GMT
> Make rootDir private and change it only once inside the class, from main.
>
> If other classes need access you can provide a getRootDir() method,
> which can check for attempts to read it before it has been set.
>
> Patricia

Suppose my program has about 20 classes and the class with main method
is MyClass provided in my original posting. Suppose one class
"Worker.java" needs to know the root directory in order to read in the
text file. Right now, Worker does NOT have a MyClass in it. But, if I
follow your method, I need:
<inside Worker.java>
MyClass class = new MyClass();
String rootDir = class.getRootDir();
...//append rootDir in the front of text file name

</inside Worker.java>

I feel it is kind of silly that in order to get to know what the root
directory it is, Worker is forced to have a MyClass in it.
Patricia Shanahan - 04 May 2007 22:04 GMT
>> Make rootDir private and change it only once inside the class, from main.
>>
[quoted text clipped - 17 lines]
> I feel it is kind of silly that in order to get to know what the root
> directory it is, Worker is forced to have a MyClass in it.

Huh? There is no more need to create an object to call a static method
than there is to access a static field. If Worker could have accessed
MyClass.rootDir, it could call MyClass.getRootDir().

Whether the root directory attribute should be a static attribute of the
MyClass class is arguable, but is orthogonal to the question of whether
it should be accessed as a variable or through an access method.

Patricia
Eric Sosman - 04 May 2007 22:08 GMT
www wrote On 05/04/07 16:06,:

>>Make rootDir private and change it only once inside the class, from main.
>>
[quoted text clipped - 17 lines]
> I feel it is kind of silly that in order to get to know what the root
> directory it is, Worker is forced to have a MyClass in it.

   In the class as you wrote it, the only way MyClass
discovers where rootDir is supposed to be is by having
somebody, somewhere, create a MyClass object and pass
the value in as an argument to the constructor.  If you
never construct a MyClass, nobody ever tells a constructor
what rootDir should be.  What should MyClass do?  Just
make something up out of thin air?

   I'm not 100% sure what you're trying to do, but if
the idea is for MyClass to "remember" the first rootDir
from the construction of the first MyClass instance,
then you can't use a static final.  Why?  Because the
static field belongs to the class and not to the instance,
and must be initialized when the class is loaded and not
later on when instances are (or aren't) constructed.

   What you might want to do instead is use a private
static variable and an accessor method, something like:

    public class MyClass {

       private static String rootDir;

       public MyClass(String dir) {
           if (rootDir == null) {
               // first instance: initialize
               rootDir = dir;
           }
       }

       public string getRootDir() {
           if (rootDir == null) {
               // optional: could just return null
               throw new IllegalStateException(...);
           }
           return rootDir;
       }
    }

Signature

Eric.Sosman@sun.com

Eric Sosman - 04 May 2007 22:28 GMT
Eric Sosman wrote On 05/04/07 17:08,:
> www wrote On 05/04/07 16:06,:
>
[quoted text clipped - 58 lines]
>        }
>     }

   Drat. Make that `public static String getRootDir()',
adding `static' and changing `string' to `String', and
the weekend had better come soon ...

Signature

Eric.Sosman@sun.com

Knute Johnson - 04 May 2007 22:10 GMT
>> Make rootDir private and change it only once inside the class, from main.
>>
[quoted text clipped - 17 lines]
> I feel it is kind of silly that in order to get to know what the root
> directory it is, Worker is forced to have a MyClass in it.

There are several ways to get your variable to other classes, such as
pass them in arguments or use a singleton.  In the end it is probably
going to be easiest to have a static variable that is visible to your
other classes.  People are going to shudder though so just don't tell
them that you are doing that.

Signature

Knute Johnson
email s/nospam/knute/

Mark Space - 05 May 2007 19:28 GMT
> I feel it is kind of silly that in order to get to know what the root
> directory it is, Worker is forced to have a MyClass in it.

I think I see what you are trying to say.  If I understand, you don't
like the fact that there is some dependency that the worker thread knows
about the MyClass class.  I think one way to fix this is to use what is
sometimes called a Strategy Pattern or Dependency Injection.  Rather
than have Worker know about MyClass, you inject the information into
Worker, thus breaking the dependency.

In plain English, I think Worker needs to know about the context in
which it's running, so let's call this dependency a "context"

public class Worker {
    private Context localCntxt;

    public Worker( Context c ) {
        localCntxt = c;
    }
    public void doStuff() {
    //...
    String rootDir = localCntxt.getRootDir();
    //...
    }
}

Now just make MyClass a type of Context object:

public class Context {    // used to be type MyClass
    private String rootDir;
    public void setRootDir( String s ) {
        rootDir = s;
    }
    public String getRootDir() {
        return rootDir;
    }
}

Feel free to stuff Context full of every sort of variable that your
classes might ever need.

Now you can easily make lots of workers all running in the same context,
or even different contexts.

public class Main {
    public void main( String [] args ) {
        Context a = new Context();
        Context b = new Context();
        Context c = new Context();

        a.setRootDir( "/" );
        b.setRootDir( "/Users/Mark/pub" );
        c.setRootDir( "/argle/bargle/blet/foo/bar" );

        Worker w1 = new Worker( a );    // Three workers all
        Worker w2 = new Worker( a );    // running in the same
        Worker w3 = new Worker( a );    // Context
        Worker w4 = new Worker( b );    // A Different Context b
        Worker w5 = new Worker( c );    // And Context c
    }
}

I hope this made some sense to you.
Patricia Shanahan - 05 May 2007 21:46 GMT
>> I feel it is kind of silly that in order to get to know what the root
>> directory it is, Worker is forced to have a MyClass in it.
[quoted text clipped - 5 lines]
> than have Worker know about MyClass, you inject the information into
> Worker, thus breaking the dependency.

This sort of approach is certainly something to keep in mind, in case
the situation gets sufficiently complicated to warrant it. I might do it
that way from the start if this were a public interface that cannot be
changed in the future.

However, if the root directory is the only thing that needs this sort of
handling, and the code can be refactored later if it looks like a good
idea, I would give this the KISS treatment.

To do what seems to be the end objective, static access to the args[0]
from the main call:

public class MyClass {
  private static String rootDir;

  public static String getRootDir() {
    // Optionally test for null and throw exception
    return rootDir;
  }

  public static void main(String[] args) {
    rootDir = args[0];
  }
}

A worker can call MyClass.getRootDir() to get the root directory name.
Short of nasty reflection abuse, a worker cannot modify rootDir.

Patricia
Mark Space - 06 May 2007 02:26 GMT
> However, if the root directory is the only thing that needs this sort of
> handling, and the code can be refactored later if it looks like a good
> idea, I would give this the KISS treatment.

I see what you are saying, and it's quite good.  However, the OP himself
raised the objection, so I thought I'd pop up with a possible solution.
 The program he's working on may in fact be rather complicated; we may
have only seen a short example here on the news group.  Or he may be
trying to learn better techniques, so the added complexity would be
useful for the example it provides. (Not that I think my example is all
that great.)  Besides, the dependency injection style is often much
easier to break down for unit testing.
Knute Johnson - 06 May 2007 02:49 GMT
>>> I feel it is kind of silly that in order to get to know what the root
>>> directory it is, Worker is forced to have a MyClass in it.
[quoted text clipped - 35 lines]
>
> Patricia

Access to rootDir needs synchronization if it is going to be accessed by
multiple threads which is guaranteed to be the case here.

Signature

Knute Johnson
email s/nospam/knute/

Tom Hawtin - 06 May 2007 03:52 GMT
>>   public static void main(String[] args) {
>>     rootDir = args[0];

> Access to rootDir needs synchronization if it is going to be accessed by
> multiple threads which is guaranteed to be the case here.

Counterpoint of pedantry: Except for obscure things such as finalisers
and assuming the initialisation of the class does not start any threads
and the class is being started as a normal program, then there is a
happens-before relation between any started threads and the single
assignment.

OTOH, I would avoid statics on the principle of no broken windows. Or I
think in the case of statics it can be termed the principle of "no
crapping on the carpet".

Tom Hawtin
Knute Johnson - 06 May 2007 04:39 GMT
>>>   public static void main(String[] args) {
>>>     rootDir = args[0];
[quoted text clipped - 7 lines]
> happens-before relation between any started threads and the single
> assignment.

Isn't that only true if assignment occurs in the constructor?  We don't
have a whole program here but I thought you could not ensure that
assignment 'happens before' any other access to this variable given the
possible instruction reordering.  On the other hand after the
constructor is complete it should be safe assuming it is not assigned again.

> OTOH, I would avoid statics on the principle of no broken windows. Or I
> think in the case of statics it can be termed the principle of "no
> crapping on the carpet".

There is no doubt that many will shudder at the thought :-).

Signature

Knute Johnson
email s/nospam/knute/

Tom Hawtin - 06 May 2007 09:28 GMT
> Isn't that only true if assignment occurs in the constructor?  We don't
> have a whole program here but I thought you could not ensure that
> assignment 'happens before' any other access to this variable given the
> possible instruction reordering.  On the other hand after the
> constructor is complete it should be safe assuming it is not assigned
> again.

The point is that the assignment is more or less the first thing the
program does. Any threads are created afterwards. It's the starting of
threads that gives the happens-before, not the static initialisation.

(For (instance) constructors, the variable would need to be final and
the instance should not leak before the end of the constructor.)

Tom Hawtin
Roman - 04 May 2007 20:13 GMT
www pisze:
> Hi,
>
[quoted text clipped - 33 lines]
>
> Thank you for your help.
you cannot assign value to final variable in an any method (even
constructors). You have to decide: final or assigne value during
declaration.
Regards,
Roman
visionset - 04 May 2007 20:35 GMT
>> I thought final variable can be assigned value once and only once. And
>> this can be done inside constructor. Cited from this web page:
>> http://renaud.waldura.com/doc/java/final-keyword.shtml in Final Field
>> part.

> you cannot assign value to final variable in an any method (even
> constructors). You have to decide: final or assigne value during
> declaration.

That is not true, a final instance variable (attribute) can be assigned
inline or in the constructor.

Signature

Mike W

Tom Hawtin - 04 May 2007 20:17 GMT
> I want to have a static field variable. I want to initiate it once and
> don't want it to be changed any more. So

>     public final static rootDir; //error: saying rootDir may not be
                         ^String
> initialized

>     public static void main(String[] args)
>     {
>         String str = args[0];
>         MyClass class = new MyClass(str);

It doesn't really make sense for this kind of variable to be static. Any
code that uses the variable, directly or indirectly, is specifying the
interpretation of class loader scope. Stick with instance variables, and
keep dependencies as narrow as possible.

Use static fields judiciously. They are good for constants[1], really
difficult for caches and hopeless for practically anything else.

Tom Hawtin

[1] Constants as in things that cannot change, not just as in the JLS
"compile-time constant".
Arne Vajhøj - 05 May 2007 16:54 GMT
> I want to have a static field variable. I want to initiate it once and
> don't want it to be changed any more. So
[quoted text clipped - 28 lines]
> this can be done inside constructor. Cited from this web page:
> http://renaud.waldura.com/doc/java/final-keyword.shtml in Final Field part.

As other have already stated then the whole construct is not good.

But to complete the understanding of final and initialization, then
the following compiles:

public class FinalDemo {
    public final static String s1;
    public final String s2;
    static {
        s1 = "A";
    }
    public FinalDemo()
    {
        s2 = "B";
    }
}

final static can be initialized in "static constructor" and
final non-static can be initialized in constructor.

Which I think makes sense.

Arne
Knute Johnson - 06 May 2007 02:51 GMT
>> I want to have a static field variable. I want to initiate it once and
>> don't want it to be changed any more. So
[quoted text clipped - 53 lines]
>
> Arne

Arne:

Is there any practical difference between;

static final String s1 = "A";

and

static final String s1;
static { s1 = "A" };

Thanks,

Signature

Knute Johnson
email s/nospam/knute/

Stefan Ram - 06 May 2007 02:58 GMT
>Is there any practical difference between;
>static final String s1 = "A";
>and
>static final String s1;
>static { s1 = "A" };

 If you deem it a »practical difference«
 that the second text will not compile.
Arne Vajhøj - 06 May 2007 03:04 GMT
>> Is there any practical difference between;
>> static final String s1 = "A";
[quoted text clipped - 4 lines]
>   If you deem it a »practical difference«
>   that the second text will not compile.

It compiles with the missing semicolon added.

Arne
Knute Johnson - 06 May 2007 03:26 GMT
>>> Is there any practical difference between;
>>> static final String s1 = "A";
[quoted text clipped - 8 lines]
>
> Arne

Picky picky a semi-colon here or there :-).

Signature

Knute Johnson
email s/nospam/knute/

Arne Vajhøj - 06 May 2007 03:06 GMT
>> But to complete the understanding of final and initialization, then
>> the following compiles:
[quoted text clipped - 15 lines]
>>
>> Which I think makes sense.

> Is there any practical difference between;
>
[quoted text clipped - 4 lines]
> static final String s1;
> static { s1 = "A" };

I do not think so.

The reason to use the "static constructor" (if you will forgive
me for using the C# term) is if you need multiple statements to
calculate the value.

Arne

Arne
Tom Hawtin - 06 May 2007 03:58 GMT
>> Is there any practical difference between;
>>
[quoted text clipped - 6 lines]
>
> I do not think so.

Yup, javap -c should show identical byte code.

> The reason to use the "static constructor" (if you will forgive
> me for using the C# term)

Nooooo!!1! "static initialiser" (although technically initialiser should
be missplled)

>                           is if you need multiple statements to
> calculate the value.

Some people prefer defining a function to do that. I prefer the static
initialiser. Note, you can't qualify with the class in the assignment
("FinalDemo.s1 = "A";"). However, never use that as an excuse to miss
the final!

Tom Hawtin


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.