a question related to "final static" field variable

W

www

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.
 
K

Knute Johnson

www said:
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.

Unfortunately not if it is also static.
 
V

visionset

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
...
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.

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.
 
S

Sanjay

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
 
W

www

Thank you all. I have realized I was wrong. But, to achieve my purpose,
do you have any suggestions?

Thank you.
 
R

Roman

www pisze:
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.
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
 
P

Patricia Shanahan

www said:
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
 
T

Tom Hawtin

www said:
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".
 
V

visionset

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.
 
W

www

Patricia said:
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.
 
P

Patricia Shanahan

www said:
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.

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
 
E

Eric Sosman

www wrote On 05/04/07 16:06,:
Patricia Shanahan wrote:




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.

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;
}
}
 
K

Knute Johnson

www said:
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.

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.
 
E

Eric Sosman

Eric Sosman wrote On 05/04/07 17:08,:
www wrote On 05/04/07 16:06,:



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;
}
}

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

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

www said:
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.

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
 
M

Mark Space

www said:
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.
 
P

Patricia Shanahan

Mark said:
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.

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
 
M

Mark Space

Patricia said:
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.
 
K

Knute Johnson

Patricia said:
Mark said:
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.

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

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

Knute Johnson

Arne said:
www said:
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.

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

Arne:

Is there any practical difference between;

static final String s1 = "A";

and

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

Thanks,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,905
Latest member
Kristy_Poole

Latest Threads

Top