Java Forum / General / March 2008
Static Variables and JAR Files
Jason Cavett - 03 Mar 2008 19:23 GMT 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.)
Knute Johnson - 03 Mar 2008 19:37 GMT > I am curious - does the scope of static variables carry across > different JAR files? [quoted text clipped - 19 lines] > 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?
 Signature Knute Johnson email s/nospam/knute/
Lew - 03 Mar 2008 20:13 GMT >> I am curious - does the scope of static variables carry across >> different JAR files? [quoted text clipped - 21 lines] > > 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.
 Signature Lew
Owen Jacobson - 04 Mar 2008 13:55 GMT > >> I am curious - does the scope of static variables carry across > >> different JAR files? [quoted text clipped - 24 lines] > 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
Mark Space - 03 Mar 2008 20:23 GMT > 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.
Eric Sosman - 03 Mar 2008 21:05 GMT >> These JAR files (AnotherPackage and EvenAnotherPackage) are being read >> in by a separate tool. When ExtendedClassA and ExtendedClassB are [quoted text clipped - 8 lines] > 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!
 Signature Eric.Sosman@sun.com
Mark Space - 03 Mar 2008 21:37 GMT >> 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 [quoted text clipped - 4 lines] > 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.
Eric Sosman - 03 Mar 2008 21:58 GMT >>> 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 [quoted text clipped - 16 lines] > 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.
 Signature Eric.Sosman@sun.com
Lew - 04 Mar 2008 00:38 GMT Mark Space wrote:
>> 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 [quoted text clipped - 4 lines] >> 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 [quoted text clipped - 3 lines] > "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: <http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.3.3.1>
> 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.
 Signature Lew
Eric Sosman - 04 Mar 2008 02:01 GMT > [...] > 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 ...
 Signature Eric Sosman esosman@ieee-dot-org.invalid
Thomas.a.mcglynn@nasa.gov - 03 Mar 2008 21:13 GMT > > These JAR files (AnotherPackage and EvenAnotherPackage) are being read > > in by a separate tool. When ExtendedClassA and ExtendedClassB are [quoted text clipped - 8 lines] > 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
Lew - 03 Mar 2008 21:15 GMT > 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.
 Signature Lew
Eric Sosman - 03 Mar 2008 20:24 GMT > 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: > [quoted text clipped - 4 lines] > 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 [quoted text clipped - 7 lines] > 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.
 Signature Eric.Sosman@sun.com
Jason Cavett - 04 Mar 2008 15:01 GMT > 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 [quoted text clipped - 10 lines] > 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.)
Eric Sosman - 04 Mar 2008 16:19 GMT > [...] > 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.
 Signature Eric.Sosman@sun.com
Adam Maass - 04 Mar 2008 08:03 GMT >I am curious - does the scope of static variables carry across > different JAR files? Short answer: yes.
> Here's the issue: > [quoted text clipped - 16 lines] > 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
Roedy Green - 04 Mar 2008 12:06 GMT On Mon, 3 Mar 2008 11:23:07 -0800 (PST), Jason Cavett <jason.cavett@gmail.com> wrote, quoted or indirectly quoted someone who said :
>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. --
Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Jason Cavett - 04 Mar 2008 15:11 GMT On Mar 4, 7:06 am, Roedy Green <see_webs...@mindprod.com.invalid> wrote:
> On Mon, 3 Mar 2008 11:23:07 -0800 (PST), Jason Cavett > <jason.cav...@gmail.com> wrote, quoted or indirectly quoted someone [quoted text clipped - 10 lines] > Roedy Green Canadian Mind Products > The Java Glossaryhttp://mindprod.com 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
Lew - 04 Mar 2008 16:30 GMT > class Base { > protected static String someInfo = null; [quoted text clipped - 12 lines] > } > } 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.
 Signature Lew
Jason Cavett - 04 Mar 2008 19:37 GMT > > class Base { > > protected static String someInfo = null; [quoted text clipped - 40 lines] > -- > Lew 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.)
Free MagazinesGet 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 ...
|
|
|