Java Forum / General / August 2007
Updates to a single class instance
unlikeablePorpoise@gmail.com - 18 Aug 2007 18:59 GMT I hope you guys can help me. I am planning to write a program with multiple packages and one of these packages will have a class with storage variables that I would like to update from any other class. I would like to know whether there is a way to "point" to a single instance of this class so that I can update the variables from anywhere in the program.
Thanks, Sarah
Knute Johnson - 18 Aug 2007 19:13 GMT > I hope you guys can help me. > I am planning to write a program with multiple packages and one of [quoted text clipped - 5 lines] > Thanks, > Sarah Search Google or Wikipedia for Singleton. The other non-OO (and don't tell anybody that I suggested this) is to use public static variables in your globals class.
 Signature Knute Johnson email s/nospam/knute/
Thomas Hawtin - 18 Aug 2007 20:38 GMT > Search Google or Wikipedia for Singleton. The other non-OO (and don't > tell anybody that I suggested this) is to use public static variables in > your globals class. Or private static variables with static get/set methods. That is to all intents and purposes the same thing as a singleton, only there is no pretend OO.
It's better to write code that doesn't use static variables, whether Singletons or not. That is easier if the code is coherent.
Tom Hawtin
Stefan Ram - 18 Aug 2007 21:00 GMT >It's better to write code that doesn't use static variables, >whether Singletons or not. That is easier if the code is >coherent. The first Java-Program a programmer encounters:
public class Main { public static void main( final java.lang.String[] args ) { java.lang.System.out.println( "Hello world!" ); }}
uses a static variable »out«.
To avoid it, we might need a new Java with:
public class Main { public static void main( final System system ) { system.out.println( "Hello world!" ); }}
Then, »system« needs to be passed to many methods and constructors, whereever it possibly might be needed.
>Or private static variables with static get/set methods. That >is to all intents and purposes the same thing as a singleton, >only there is no pretend OO. An example would be the getter:
java.lang.Thread.currentThread()
It is not the same as a singleton, because there is no intention that the result is the /only/ instance of its class.
To avoid it, we'd need to pass another object, because, logically, the current thread is not a system property.
public class Main { public static void main( final System system, final Thread currentThread ) { system.out.println( "Hello world!" ); }}
This also would have to be passed to every method that possibly might need it some day or otherwise many signatures will need to change in order to add it as a parameter.
Lew - 18 Aug 2007 21:09 GMT Thomas Hawtin writes:
>> Or private static variables with static get/set methods. That >> is to all intents and purposes the same thing as a singleton, >> only there is no pretend OO.
> An example would be the getter: > [quoted text clipped - 3 lines] > intention that the result is the /only/ instance of its > class. This is not a static variable but a static method - whole other thing.
 Signature Lew
Eric Sosman - 18 Aug 2007 19:40 GMT > I hope you guys can help me. > I am planning to write a program with multiple packages and one of > these packages will have a class with storage variables that I would > like to update from any other class. I would like to know whether > there is a way to "point" to a single instance of this class so that I > can update the variables from anywhere in the program. ... effectively making all of them "global variables." Global variables are very convenient when you start to write a program, but they have drawbacks that tend to become more and more troublesome as the program grows and changes. Be warned! Global variables deserve their ill repute.
... but if you're sure this is what you want, it sounds like you should use what's called a "singleton:" a class with exactly one instance (you can enforce this by making the only constructor private and calling it exactly once from within the class). You could make that one instance be a member of the class:
public class Global { private Global() { } public static final Global INSTANCE = new Global(); }
... or you could keep the instance private and use an accessor method to provide it to the rest of the program:
public class Global { private Global() { } private static final Global INSTANCE = new Global(); public static Global getInstance() { return INSTANCE; } }
For the variables the Global instance contains you have a similar choice: Make them public, or keep them private and write methods to set and retrieve their values. Usually the latter is the better choice, because it allows for much more flexibility: it's easy to make validity checks on the values that are set, it's easy to keep valueB up to date when valueA changes, and so on.
You can even do without the Global instance altogether, making all the variables static members of the Global class itself:
public class Global { private Global() { }
private static int valueA; public static int getValueA() { return valueA; } public void setValueA(int newValue) { if (newValue < 42) throw new IllegalArgumentException(...); valueA = newValue; } ... }
Keep in mind, though, that all of these techniques are just variations on the global variable, a construct that is capable of causing a surprising amount of trouble.
 Signature Eric Sosman esosman@ieee-dot-org.invalid
unlikeablePorpoise@gmail.com - 18 Aug 2007 20:42 GMT Thanks for your replies. I tried to use a singleton, but for some reason each attempt to create the singleton from different classes says the object is null (the second and subsequent calls should say that the object has been created). Here's the test code:
package org.collector;
public class Collector{
private Collector() {}
private static Collector ref;
public static synchronized Collector getCollectorObject() { if(ref == null) { System.out.println("ref is null"); ref = new Collector(); } else { System.out.println("ref exists"); }
return ref; } }
When I call 'Collector col = Collector.getCollectorObject();' twice in two different classes, it returns "ref is null". However, if I do this twice in the same class method, ie
Collector col = Collector.getCollectorObject(); Collector col2 = Collector.getCollectorObject();
I get the expected result:
"ref is null" "ref exists"
Just to clarify, the Collector singleton is in its own package, and the methods that have to access it are in different packages.
Am I missing something here? Or is the singleton limited to use one class or package?
Thanks for your help! Sarah
> unlikeablePorpo...@gmail.com wrote: > > I hope you guys can help me. [quoted text clipped - 65 lines] > Eric Sosman > esos...@ieee-dot-org.invalid Lew - 18 Aug 2007 21:16 GMT > Thanks for your replies. Simply to avoid top-posting will indicate thanks.
> package org.collector; Are you an org, named "collector"?
The org domain implies non-profit organizations.
> public class Collector{ > [quoted text clipped - 3 lines] > > public static synchronized Collector getCollectorObject() Since everything in Java is an object, having "Object" in your method name is redundant.
> { > if(ref == null) This is overuse of lazy initialization.
Just establish the object in the class initializer.
> { > System.out.println("ref is null"); [quoted text clipped - 12 lines] > two different classes, it returns "ref is null". However, if I do this > twice in the same class method, ie I don't know exactly why this happens, but I bet you'll get rid of the problem altogether like this
public class Collector { private Collector() { } private static final Collector UNIQUE = new Collector(); // this has the advantage of making the variable non-replaceable // and eliminating the need for synchronization
public static Collector getCollector() { return UNIQUE; } }
 Signature Lew
unlikeablePorpoise@gmail.com - 18 Aug 2007 21:46 GMT > I don't know exactly why this happens, but I bet you'll get rid of the problem > altogether like this [quoted text clipped - 17 lines] > -- > Lew I am still getting the same problem with your suggestion implemented in my code.
Surely the singleton design pattern can work in multiple classes/ packages. Has anybody gotten this to work before?
Thanks, Sarah
Eric Sosman - 18 Aug 2007 22:05 GMT (Please position a reply after the message you're replying to, or interspersed with it for a point-by-point reply. Backward things read to harder it's.)
> Thanks for your replies. I tried to use a singleton, but for some > reason each attempt to create the singleton from different classes [quoted text clipped - 42 lines] > Am I missing something here? Or is the singleton limited to use one > class or package? With the code as you've shown it, I don't understand how the behavior you report can occur. Is the Collector class truly as lightweight as shown? Or have you deleted other bits of code for brevity's sake? That's usually a good idea, but you may have omitted something important -- for instance, a method that accesses `ref' while synchronizing on something other than Collector.class, or not synchronizing at all.
As for the interaction of package membership and singletons: There is none. The package forms part of the complete name of a class (it's org.collector.Collector, not just Collector), and package membership affects the reach of some access levels (but not public and not private). Package membership has nothing to do with whether `ref' is or isn't null, nor with what the method synchronizes on, nor with how many times the constructor is used.
Perhaps the secret lies in how you call the method "twice in two different classes:" if you run one class' main method and let the program finish, and then run the other class' main method and let its program finish, these executions are in two different universes, separated by a Big Crunch and a Big Bang. Nothing that happened in one execution (aside from modifying persistent storage like a file system) affects what happens in the other. When the second program runs, the Collector class is loaded anew -- it is in this sense a "different" Collector class -- and the singleton that existed in the first program is long gone. The second program will then create a new singleton Collector.
If you need a singleton that persists across different JVM instances, you'll need to work harder. It's doable (I think; I haven't done it myself), but takes you into the arena of object serialization and of debates about what "the same" means across what amounts to a reboot.
By the way, you can visit http://www.collector.org/ to learn that there's an organization out there who might distribute Java code of their own. If they do, their package names will begin with org.collector, and there will be confusion and perhaps bad consequences if someone tries to use your code and their code in the same program. Unless you're part of collector.org, you should probably choose another package name.
 Signature Eric Sosman esosman@ieee-dot-org.invalid
unlikeablePorpoise@gmail.com - 18 Aug 2007 22:16 GMT > (Please position a reply after the message you're replying > to, or interspersed with it for a point-by-point reply. [quoted text clipped - 93 lines] > Eric Sosman > esos...@ieee-dot-org.invalid I think you are right. I am attempting this in two different main() methods. Damn.
Thanks, Sarah
Daniel Pitts - 19 Aug 2007 20:57 GMT On Aug 18, 2:16 pm, unlikeablePorpo...@gmail.com wrote:
> > (Please position a reply after the message you're replying > > to, or interspersed with it for a point-by-point reply. [quoted text clipped - 99 lines] > Thanks, > Sarah So, you mean you want a piece of datum that can persist between execution of your program, and even different programs...
If you want multiple classes to be able access this object (I'll call these classes Clients) concurrently, then perhaps the state of this object should be maintained in a its own class (I'll call this the Server). The Clients will connect to the Server, probably through Sockets, Possibly using RMI or some other remoting protocol, and ask the server to manipulate and report on the state of your "singleton".
If, however, all you need is that the state of your "singleton" be maintained across multiple runs (that never ever overlap), then you want to persist your "singleton" to either a disk, database, or some other persistence technology.
If you really only care about the current execution, then just using the standard "Singleton" pattern may be good enough, although I would suggest using the Dependency Injection pattern instead where possible/ feasible.
Theme - 21 Aug 2007 17:31 GMT On Aug 18, 10:42 pm, unlikeablePorpo...@gmail.com wrote:
> package org.collector; > [quoted text clipped - 32 lines] > "ref is null" > "ref exists" IMHO it's ok, since it ptints to System.out message from block with lazy initialization, it does not return null, does it?
private Collector() {} private static Collector ref;
public static synchronized Collector getCollectorObject() { if(ref == null) { System.out.println("lazy initialization! here, IMHO static will be better..."); ref = new Collector(); } else { System.out.println("ref exists"); }
return ref;//does not return null object in any case! } (first time will print to System.out "lazy initialization! here...") And yes, removing lazy initialization will make class more concurrent- compatible.
Good Luck, Theme
Roedy Green - 18 Aug 2007 21:42 GMT >I am planning to write a program with multiple packages and one of >these packages will have a class with storage variables that I would >like to update from any other class. I would like to know whether >there is a way to "point" to a single instance of this class so that I >can update the variables from anywhere in the program. the simplest way is to give it some static public members or static public setter methods. The fancy pants way is to use a Singleton. See http://mindprod.com/jgloss/singleton.html
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
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 ...
|
|
|