Static Variables and JAR Files

J

Jason Cavett

I am curious - does the scope of static variables carry across
different JAR files?

Here's the issue:

BaseClass is in "BaseClasses.jar"
ExtendedClassA extends BaseClass is in "AnotherPackage.jar"
ExtendedClassB extends BaseClass is in "EvenAnotherPackage.jar"

BaseClass has a static object (ObjectX). Now, normally, this static
object is static across all of the subclasses. However...

These JAR files (AnotherPackage and EvenAnotherPackage) are being read
in by a separate tool. When ExtendedClassA and ExtendedClassB are
used within the context of this tool, ObjectX is instantiated twice
and has two separate values. As far as I can tell, the tool runs
ExtendedClassA and ExtendedClassB within the same JVM, so I am unsure
of what is going on.

Does anybody have any insight into what is going on here? (Sorry for
being vague. I'm not actually working the project, but I'm curious
from an academic standpoint. Another group ran across this problem
today.)
 
K

Knute Johnson

Jason said:
I am curious - does the scope of static variables carry across
different JAR files?

Here's the issue:

BaseClass is in "BaseClasses.jar"
ExtendedClassA extends BaseClass is in "AnotherPackage.jar"
ExtendedClassB extends BaseClass is in "EvenAnotherPackage.jar"

BaseClass has a static object (ObjectX). Now, normally, this static
object is static across all of the subclasses. However...

These JAR files (AnotherPackage and EvenAnotherPackage) are being read
in by a separate tool. When ExtendedClassA and ExtendedClassB are
used within the context of this tool, ObjectX is instantiated twice
and has two separate values. As far as I can tell, the tool runs
ExtendedClassA and ExtendedClassB within the same JVM, so I am unsure
of what is going on.

Does anybody have any insight into what is going on here? (Sorry for
being vague. I'm not actually working the project, but I'm curious
from an academic standpoint. Another group ran across this problem
today.)

I'm curious how you instantiate a static object? What tool are they using?
 
L

Lew

Knute said:
I'm curious how you instantiate a static object? What tool are they using?

The scope of a static class variable is the entire execution of the JVM once
the class is loaded. Its accessibility is that declared for it.

When you say "ObjectX is instantiated twice and has two separate values",
first of all, instance names are supposed to begin with a lower-case letter.
Anyway, do you mean there are two simultaneous instances of
'BaseClass.ObjectX' (we really have to improve these names!)? Or do you mean
there is one variable 'BaseClass.ObjectX' that points to different objects at
different times?

If it's the first case, two simultaneous instances of the "same" static
variable, it's because the class was loaded two different times by two
different ClassLoader instances. That causes the "same" class to actually be
two different classes, one belonging to each ClassLoader.

If it's the second case, the same variable but it points to different objects
at different times, it's because something changed what the variable points to
after it was set the first time.
 
M

Mark Space

Jason said:
These JAR files (AnotherPackage and EvenAnotherPackage) are being read
in by a separate tool. When ExtendedClassA and ExtendedClassB are
used within the context of this tool, ObjectX is instantiated twice
and has two separate values. As far as I can tell, the tool runs
ExtendedClassA and ExtendedClassB within the same JVM, so I am unsure
of what is going on.

Obviously, when you make a new class via inheritance, it gets it's own
copy of the static variable. So there will be one static for the parent
class, and one for the child class. The static is a "class variable"
and since there are two classes (parent and child) there are two static
variables.

There could be other things going on. The tool may be using
ClassLoaders to load the jar files. When a separate ClassLoader is
used, classes loaded under separate ClassLoaders are separate classes.
Even if there was no inheritance involved, there may still be two
separate ObjectX and two copies of the static variable. If this is the
case, there will also be two copies of the class object itself (it gets
loaded twice, to separate memory areas) which is the root cause of this
particular static issue.


You may need to look at the documentation of the tool you are using, and
decide how you need to correctly deal with this situation. Just
curious: what tool are we talking about here? Like maybe a web container?


There could be other issues too. Fire up the debugger, read the source
code, decompile some tool code, or bug the manufacturer support site.
Stuff happens.
 
E

Eric Sosman

Jason said:
I am curious - does the scope of static variables carry across
different JAR files?

You're asking a rather detailed question, so it would be
good to ask it in precise language. What, exactly, do you
mean by "scope?" You don't seem to be using the word in the
way the Java Language Specification does.
Here's the issue:

BaseClass is in "BaseClasses.jar"
ExtendedClassA extends BaseClass is in "AnotherPackage.jar"
ExtendedClassB extends BaseClass is in "EvenAnotherPackage.jar"

BaseClass has a static object (ObjectX). Now, normally, this static
object is static across all of the subclasses. However...

Precision again: What do you mean by "static object?" As
far as I can see, objects cannot be static. I *think* what you
mean is that BaseClass has a static member variable that refers
to an instance of the ObjectX class.
These JAR files (AnotherPackage and EvenAnotherPackage) are being read
in by a separate tool. When ExtendedClassA and ExtendedClassB are
used within the context of this tool, ObjectX is instantiated twice
and has two separate values. As far as I can tell, the tool runs
ExtendedClassA and ExtendedClassB within the same JVM, so I am unsure
of what is going on.

Does anybody have any insight into what is going on here? (Sorry for
being vague. I'm not actually working the project, but I'm curious
from an academic standpoint. Another group ran across this problem
today.)

A class is identified by its fully-qualified name *and* by
the ClassLoader instance that loaded it. If two distinct loaders
load "net.worth.Zero" -- even if they load it from the very same
Zero.class file -- there will be two distinct classes both named
"net.worth.Zero" floating around in the JVM. Something like an
IDE might find this convenient, because it would allow you to
edit and recompile Zero.java and then load the newly-compiled
class without restarting the JVM or somehow force-unloading the
old class.

This "separate tool" you speak of may be using multiple class
loaders for one reason or another. You could try getClass() on
both the ObjectX instances to find out whether they are actually
of different classes.
 
E

Eric Sosman

Mark said:
Obviously, when you make a new class via inheritance, it gets it's own
copy of the static variable. So there will be one static for the parent
class, and one for the child class. The static is a "class variable"
and since there are two classes (parent and child) there are two static
variables.

Please predict the output of this simple demonstration, and
then test your prediction:

class Foo {
static int count;

public static void main(String[] unused) {
Foo.count = 1;
Bar.count = 2;
System.out.println("Foo.count = " + Foo.count);
System.out.println("Bar.count = " + Bar.count);
}
}

class Bar extends Foo {
// Mark says a copy of `count' is inherited here
}

If Foo.count and Bar.count are two distinct variables, the
output will show two different values. If it shows the same
value for both, they cannot be distinct. Place your bets!
 
T

Thomas.a.mcglynn

Obviously, when you make a new class via inheritance, it gets it's own
copy of the static variable. So there will be one static for the parent
class, and one for the child class. The static is a "class variable"
and since there are two classes (parent and child) there are two static
variables.

To clarify this since I think it could be misinterpreted:
If you try the following program:

class A {
static String var = "ClassA";
}
class B extends A {
}

public class Test {
public static void main(String[] args) {
B.var = "SetInProgram";
System.out.println("A.var is:"+A.var);
System.out.println("B.var is:"+B.var);
}
}

The output of this program

A.var is:SetInProgram
B.var is:SetInProgram

shows that there is only one field even though B extends A. I can add
a declaration to B:

class B extends A {
static String var = "ClassB";
}

Now when I run this I get:

A.var is:ClassA
B.var is:SetInProgram

The definition in B hides the one in A (or 'shadows' I'm never quite
sure of which terminology is used where) -- though a user could still
reference it as A.var.

So regardless of the number of times we extend a class, we declare
only a single instance of its static fields. However if the new class
does not hide the original field, we can use a new name for the field.

Regards,
Tom McGlynn
 
L

Lew

Mark said:
Obviously, when you make a new class via inheritance, it gets it's own
copy of the static variable. So there will be one static for the parent
class, and one for the child class. The static is a "class variable"
and since there are two classes (parent and child) there are two static
variables.

This isn't exactly correct. If the child class does not declare a hiding
static variable then there is only the parent-class variable. There isn't by
default a duplicate version in the child class.
 
M

Mark Space

Eric said:
Please predict the output of this simple demonstration, and
then test your prediction:

Well clearly I was mistaken. That's pretty frustrating too because I
looked this up before I posted, and the documentation and examples
seemed to indicate that there would be a copy of a static variable.

Even the JLS doesn't really say, it just says that non-private fields
are inherited. I'm not sure how one is supposed to determine when
documentation, including the JLS, should be taken at face value and when
one has to experiment carefully to determine what the docs actually meant.

I'm not sure what else to add, other than I'm really fuming over having
missed that.
 
E

Eric Sosman

Mark said:
Well clearly I was mistaken. That's pretty frustrating too because I
looked this up before I posted, and the documentation and examples
seemed to indicate that there would be a copy of a static variable.

Even the JLS doesn't really say, it just says that non-private fields
are inherited. I'm not sure how one is supposed to determine when
documentation, including the JLS, should be taken at face value and when
one has to experiment carefully to determine what the docs actually meant.

I'm not sure what else to add, other than I'm really fuming over having
missed that.

Standardese can sometimes be as opaque as a meter of mud.
Perhaps the thing to remember here is that "inherit" does not
mean "make a copy of." The subclass "inherits" the accessible
members of its superclasses, but that doesn't mean it makes
its own local copies of them. They continue to "reside in" or
"belong to" the superclasses, although they can be accessed
through the subclass.
 
L

Lew

Eric said:
Standardese can sometimes be as opaque as a meter of mud.
Perhaps the thing to remember here is that "inherit" does not
mean "make a copy of." The subclass "inherits" the accessible
members of its superclasses, but that doesn't mean it makes
its own local copies of them. They continue to "reside in" or
"belong to" the superclasses, although they can be accessed
through the subclass.

The JLS actually clarifies this in an example of when a static field is hidden
and when it isn't:
the simple name x now refers to the field Point.x.
Code in class Test may still refer to that same field as super.x.
Therefore, the output from this variant program is:

2 2

But generally I'm having the same trouble finding as clear a statement of this
principle as I remember reading somewhere.
 
E

Eric Sosman

Lew said:
[...]
But generally I'm having the same trouble finding as clear a statement
of this principle as I remember reading somewhere.

Maybe my "meter of mud" was an understatement ...
 
A

Adam Maass

Jason Cavett said:
I am curious - does the scope of static variables carry across
different JAR files?

Short answer: yes.
Here's the issue:

BaseClass is in "BaseClasses.jar"
ExtendedClassA extends BaseClass is in "AnotherPackage.jar"
ExtendedClassB extends BaseClass is in "EvenAnotherPackage.jar"

BaseClass has a static object (ObjectX). Now, normally, this static
object is static across all of the subclasses. However...

These JAR files (AnotherPackage and EvenAnotherPackage) are being read
in by a separate tool. When ExtendedClassA and ExtendedClassB are
used within the context of this tool, ObjectX is instantiated twice
and has two separate values. As far as I can tell, the tool runs
ExtendedClassA and ExtendedClassB within the same JVM, so I am unsure
of what is going on.

Does anybody have any insight into what is going on here? (Sorry for
being vague. I'm not actually working the project, but I'm curious
from an academic standpoint. Another group ran across this problem
today.)

Perhaps BaseClasses.jar is available to two different classloaders. "static"
is scoped on a per-classloader basis.

-- Adam Maass
 
R

Roedy Green

BaseClass has a static object (ObjectX). Now, normally, this static
object is static across all of the subclasses. However...

Please post some example code. There is no such thing as a "static
object". If you want a singleton, it will have to be a static
reference in only one class.
 
O

Owen Jacobson

The scope of a static class variable is the entire execution of the JVM once
the class is loaded. Its accessibility is that declared for it.

This isn't necessarily true. A single class Foo can be loaded in
multiple class loaders so long as the common parents do not also load
Foo. This means that static members of Foo may exist more than once:
each time the Foo class is loaded within a classloader, another
occurrence of Foo's static members comes into being . Foo's static
initializer is also run each time the class is loaded.

Consider the following class Foo:

package dyn;

public class Foo {
static {
System.out.println("Class " + Foo.class + " loaded on CL="
+ Foo.class.getClassLoader());
}
}

This class is not available on the bootstrap classpath: it's in a
separate directory called Dynamic relative to the working directory.
The main class

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class DCL {
public static void main(String[] args) throws
MalformedURLException,
ClassNotFoundException, InstantiationException,
IllegalAccessException {
URLClassLoader cl1 =
new URLClassLoader(
new URL[] { new URL(
"file:Dynamic/") });
cl1.loadClass("dyn.Foo").newInstance();

URLClassLoader cl2 =
new URLClassLoader(
new URL[] { new URL(
"file:Dynamic/") });
cl2.loadClass("dyn.Foo").newInstance();
}
}

generates the output

Class class dyn.Foo loaded on CL=java.net.URLClassLoader@2e7263
Class class dyn.Foo loaded on CL=java.net.URLClassLoader@5eb0a9

Since Cavett hasn't told us what this "separate tool" is, it's
entirely possible that it's engaging in some dynamic classloading and
actually is running the static initializer for ObjectX twice (and
initializing static final members twice).

-o
 
J

Jason Cavett

     Precision again: What do you mean by "static object?"  As
far as I can see, objects cannot be static.  I *think* what you
mean is that BaseClass has a static member variable that refers
to an instance of the ObjectX class.

You are correct. Thanks for the correction.
     A class is identified by its fully-qualified name *and* by
the ClassLoader instance that loaded it.  If two distinct loaders
load "net.worth.Zero" -- even if they load it from the very same
Zero.class file -- there will be two distinct classes both named
"net.worth.Zero" floating around in the JVM.  Something like an
IDE might find this convenient, because it would allow you to
edit and recompile Zero.java and then load the newly-compiled
class without restarting the JVM or somehow force-unloading the
old class.

     This "separate tool" you speak of may be using multiple class
loaders for one reason or another.  You could try getClass() on
both the ObjectX instances to find out whether they are actually
of different classes.

Alright. I figured it might be something like that. I'm curious if
there is any possible way for static member variables to carry across
JVMs. (I would guess that there isn't, but I figured I would ask.)
 
J

Jason Cavett

Please post some example code. There is no such thing as a "static
object".  If you want a singleton, it will have to be a static
reference in only one class.

Yeah, I realize that I misspoke. Thank you for the correction. I,
instead, have a static member variable that refers to an object.

Anyway...the example code is pretty simple.

class Base {
protected static String someInfo = null;

public Base() {
// instantiate
}
}

class Child extends Base {

public Child() {
if(Base.someInfo == null) {
someInfo = new String("String Here");
}
}
}


I have a couple other children that also extend base and, if someInfo
is null, they give the String their own value. However, when I use
this 3rd party application to load up the different children classes,
someInfo is always null upon load and will be set with the string
specific to that child.

After doing some testing, I printed out the information of the String
and it is NOT the same String. (AKA - Different classloaders are
probably being used to load up the children.) What I'm wondering is
whether or not it is possible to stop this from happening. AKA -
someInfo will refer to the same object across all classloaders.

Thanks
 
E

Eric Sosman

Jason said:
[...]
Alright. I figured it might be something like that. I'm curious if
there is any possible way for static member variables to carry across
JVMs. (I would guess that there isn't, but I figured I would ask.)

It seems far-fetched, but I won't rule it out because
I'm unfamiliar with RMI. If there's a way two JVM's can
share the same (for some value of "same") object, I'd bet
that's where to hunt for it.
 
L

Lew

Jason said:
class Base {
protected static String someInfo = null;

public Base() {
// instantiate
}
}

class Child extends Base {

public Child() {
if(Base.someInfo == null) {
someInfo = new String("String Here");
}
}
}

This code runs an inherent risk of multiple instantiation of the 'someInfo'
variable, in a multi-threaded context.
I have a couple other children that also extend base and, if someInfo
is null, they give the String their own value.

So what is 'someInfo' supposed to be when multiple children instantiate? It's
a suspect pattern to have different children instantiate a parent-class static
member with different values. Part of the problem is that it creates a
dependency between not only the parent to the child class, but between child
classes. Now they have to be aware of the semantics of specific String (not
enum?!) values in a shared variable.

Another problem is that class loading in a different order can cause
non-deterministic behavior - on some runs the 'someInfo' will settle
eventually to one value, on other runs to a different value.

If multiple threads grab the class, even via the same class loader, each
thread could instantiate the variable to a different value and use that value
locally throughout its run. The value change might not be visible to the
other or any subsequent thread.

It is likely that removing this static variable will be a better solution than
trying to get all that right.
 
J

Jason Cavett

This code runs an inherent risk of multiple instantiation of the 'someInfo'
variable, in a multi-threaded context.


So what is 'someInfo' supposed to be when multiple children instantiate?  It's
a suspect pattern to have different children instantiate a parent-class static
member with different values.  Part of the problem is that it creates a
dependency between not only the parent to the child class, but between child
classes.  Now they have to be aware of the semantics of specific String (not
enum?!) values in a shared variable.

Another problem is that class loading in a different order can cause
non-deterministic behavior - on some runs the 'someInfo' will settle
eventually to one value, on other runs to a different value.

If multiple threads grab the class, even via the same class loader, each
thread could instantiate the variable to a different value and use that value
locally throughout its run.  The value change might not be visible to the
other or any subsequent thread.

It is likely that removing this static variable will be a better solution than
trying to get all that right.

Good points. I'll make sure to pass them along. (Again, this is not
my project...I'm just asking because I'm academically curious.)
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top