5

Basically, I want to create Counter objects, all they have to do is hold number values. And in my resetCounters method, I would like to reset each object's values. This is probably very easy, but I'm a newb.

public class Counter
{
    Random number = new Random();

    Counter()
    {
        Random number = new Random();
    }

    public Random getNumber()
    {
        return number;
    }

    public void setNumber(Random number)
    {
        this.number = number;
    }

    public static void main(String[] args) 
    {
        Counter counter1 = new Counter();
        Counter counter2 = new Counter();
        Counter counter3 = new Counter();
        Counter counter4 = new Counter();
        Counter counter5 = new Counter();

    }

    public static void resetCounters()
    {

    }
    }
kosa
  • 65,990
  • 13
  • 130
  • 167
  • There is something not correct in the program. You are not calling resetCounter() anywhere. – kosa Jul 09 '12 at 18:50
  • I think he is asking about what to put in the resetCounters() code. – Matt Westlake Jul 09 '12 at 18:51
  • True, I haven't called it yet in main, but I don't understand what code I need to put inside my resetCounters method. –  Jul 09 '12 at 18:51
  • 1
    Well, given that the counters are all local variables in `main`, there's no possible implementation to do what the OP wants. – Louis Wasserman Jul 09 '12 at 18:51
  • Sorry I'm very inexperienced. So I have to declare the counters inside the class? –  Jul 09 '12 at 18:52
  • What does resetting mean in your context? Set the values to 0? I don't quite see what their initial state is, and where they're modified, so they can be reset. Could you please add more details? – Morfic Jul 09 '12 at 18:52
  • he could write a for loop as long as he continues using the basis of counter+i as his naming scheme. – Matt Westlake Jul 09 '12 at 18:52
  • @Grove Basically I would just like to reset the "number" value for each object to 0. It's a learning exercise. –  Jul 09 '12 at 18:54
  • Then you could add a `reset()` method in the counter class, which sets the value to 0, and use Makoto's reply below, by invoking it for each counter. – Morfic Jul 09 '12 at 18:56
  • 1
    Is this homework? If yes, please tag. @LouisWasserman: I feel there are at least two options... – krlmlr Jul 09 '12 at 18:56
  • It really depends on what the OP wants, but at a minimum it'll require reorganizing the code that's already been provided. – Louis Wasserman Jul 09 '12 at 18:57
  • @LouisWasserman: ...and, en passant, learn about Factories. Why not? – krlmlr Jul 09 '12 at 18:58
  • ...Huh? Factories seem...overkill. Either class-level variables, or arrays, or some other way of organizing the counters is appropriate. – Louis Wasserman Jul 09 '12 at 18:59
  • @LouisWasserman: Care to provide an answer? We could discuss it then. – krlmlr Jul 09 '12 at 19:01
  • @user946850 No it's not homework, it's actually a learning exercise for Java training at work. I had no prior experience. So I guess it's comparable –  Jul 09 '12 at 19:05

5 Answers5

5

First option: Memorize each instance of Counter.

Collect each instance of Counter in some static collection. To reset all, simply iterate over all items in the collection. But strong references are too strong for this -- make sure it's a collection of weak references.

Remarks:

  1. Using weak references will avoid the issue that the Counter objects exist indefinitely only because of their reference from within the static collection. Objects that are referred to only by weak references are eventually collected by the garbage collector.
  2. The collection of every instance can be achieved by declaring the Counter constructor private and allowing only construction through a static member function which will also do the registration. (Or use some other incarnation of the Factory pattern.) I believe a factory is the way to go here, since each construction of an object has to carry out also a side effect. But perhaps it will make do to have the Counter constructor register this with the static collection.

Second option: Generation counter

Keep a static generation counter of type long, and also a copy of this counter in each instance. When resetting all counters, just increase the static generation counter. The getNumber() method will then check the static generation counter against its own copy and reset the counter if the static generation counter has changed.

(I don't really know the "official" name for this trick. How to zero out array in O(1)?)

Community
  • 1
  • 1
krlmlr
  • 25,056
  • 14
  • 120
  • 217
  • Where is a reference to garbage collection here? Your comments on our answers apply here too. – GETah Jul 09 '12 at 19:19
  • Forgive me if I'm wrong, but this example is a bit trivial to use `WeakReference`s, don't you think? From the ground up, we have a static collection, the contents of which always represents all the counters we care about. There is no memory leak because the program always cares about the counters in that collection. – Nicole Jul 11 '12 at 17:21
  • Ok, now I am asking for forgiveness. I just read the `CounterFactory` answer, where you *really would* need WeakReferences (since the static collection is hidden behind a dumb construction method that could be used an unlimited number of times). It just didn't make sense to me in the context of a directly-known, limited static collection. – Nicole Jul 11 '12 at 17:24
4

Since we have no idea what the context is, we can't narrow down the specific thing you should do is, but the options that occur to me immediately are...

1: If the counters have distinct meanings beyond "counter1, counter2, counter3," then they could be static class variables (with more useful names).

   public class Counter {
       static Counter counter1 = new Counter();
       ...
       public void resetCounters() {
         counter1.clear();
         counter2.clear();
          ...
        }
      }

2: If you just want several distinct counters, and they have no particular meaning by themselves, and you know that there will only ever be five of them, then you should use an array:

public class Counter {
  public static void main(String[] args) {
    Counter[] counters = {new Counter(), new Counter(), new Counter(), new Counter(), new Counter()};
    ...
  }
  static void resetCounters(Counter[] counters) {
    for (Counter c : counters) {
      c.reset();
    }
  }
}

Or, if you're planning to have an arbitrary number of them, you might try one of the fancier factory patterns. It really depends on what the context is, what you're actually trying to do, and what the point of the exercise is.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Great usage of the [YAGNI](http://en.wikipedia.org/wiki/YAGNI) pattern (one of the most important ones! ;-) – krlmlr Jul 09 '12 at 19:28
2

Since you're working with a large number of objects, you would be well served placing them in some sort of collection, like an ArrayList.

List<Counter> counters = new ArrayList<Counter>();

Insert all of your counters into there using the .add() method. Then, you can author your resetCounters() method in this manner:

public static void resetCounters(List<Counter> counters) {
    for(Counter c: counters) {
        // perform some action to reset the counters, as described by you
    }
}
Makoto
  • 104,088
  • 27
  • 192
  • 230
  • All `Counter` objects will live forever, since the garbage collector will think that they are used through the `counters` collection. – krlmlr Jul 09 '12 at 18:59
  • 2
    That depends on your definition of "reset". If you want to overwrite the contents in the object, this works fine. If you want to send all Counter objects in for garbage collection, then employ the use of [`List.clear()`](http://docs.oracle.com/javase/7/docs/api/java/util/List.html#clear()). – Makoto Jul 09 '12 at 19:06
  • Well, no. I believe the OP means that `reset()` clears the value of all existing `Counter` instances, whatever "clear" means here. But consider a counter that has been `.add()`ed to the `counters` but has no other reference pointing to it. It is essentially dead, but still will be `reset`. Does this make sense to you? – krlmlr Jul 09 '12 at 19:27
  • It's not sinking in 100%. The only way that the OP would be able to effectively maintain all references of a Counter object would be to place them in some sort of collection. Is there some other way that you can keep track of object instances that doesn't involve code for each and every object? – Makoto Jul 09 '12 at 20:16
  • See [my answer](http://stackoverflow.com/a/11401288/946850) right below :-) First option. – krlmlr Jul 09 '12 at 20:17
1

The easiest and elegant way of achieving what you want is keeping a reference to all created objects somewhere, in a factory for example and resetting them when needed.

public class CounterFactory{
      private List<Counter> counters = new ArrayList<Counter>();

      public Counter createCounter(){
          Counter c = new Counter();
          counters.add(c);
          return c;
      }
      public void resetCounters(){
          for(Counter c : counters) c.setNumber(new Random());
      }
}

And in the main method, use it this way:

public static void main(String[] args) 
{
    CounterFactory f = new CounterFactory();
    Counter counter1 = f.createCounter();
    Counter counter2 = f.createCounter();
    Counter counter3 = f.createCounter();
    Counter counter4 = f.createCounter();
    Counter counter5 = f.createCounter();

    // Reset all counters
    f.resetCounters();
}
GETah
  • 20,922
  • 7
  • 61
  • 103
  • The same applies here: All `Counter` objects will live forever, since the garbage collector will think that they are used through the `counters` collection. – krlmlr Jul 09 '12 at 19:02
  • That is your choice in the factory, just add a `clear` method where you clean up your list and you are done. – GETah Jul 09 '12 at 19:14
  • What would this `clear` method do, and when would it be called? – krlmlr Jul 09 '12 at 19:57
  • It will clear the list and will be called when the user thinks he/she needs to clean up the list. If the counters have to leave forever then it is the user's choice. – GETah Jul 09 '12 at 20:06
  • 1
    So `clear` just cleans the list. But what about all those counters hanging around -- they will not be reset anymore when `resetCounters` is called. Or does `clear` distinguish between counters still in use, and counters that are obsolete and can be removed -- if so, how? – krlmlr Jul 09 '12 at 20:08
  • The answer to your question is beyond the problem we are trying to resolve here. The OP's question is "I would like to reset **each** object's values" which means that when we reset counters, we reset them all with no distinction whatsoever – GETah Jul 09 '12 at 20:32
  • 1
    You might want to check out [this article about weak references](http://weblogs.java.net/blog/2006/05/04/understanding-weak-references?force=530) as well as the [Java docs](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html). (Actually, I have provided both links in [my answer](http://stackoverflow.com/a/11401288/946850).) Please do, and get back to me if you have further questions. – krlmlr Jul 09 '12 at 20:35
  • I agree with @user946850 here. Since you've abstracted (and therefore hidden) the counter-collecting from the creation of Counters, a user of your class may just use and throw away Counters like any old object, expecting the ones they still hold references to be reset when `resetCounters` is called. But, any they threw away will be retained as a memory leak unless WeakReferences are used. But with that caveat, clever solution, I like it. – Nicole Jul 11 '12 at 17:27
1

1. First of all there is not need to Initialize a Random nos as an instance variable,just have a Object Reference Varaible, as you are already initializing it in the Constructor.

eg:

Random number;

2. Create an ArrayList and store all the Counter objects.

ArrayList<Counter> arr = new ArrayList<Counter>();

3. Add each counter object in to the ArrayList.

4. Make reset function Non-static..there is no need for it to be static.

5. Iterate and reset...

for (Counter c : arr){

      c.reset();
    }

6. In reset() do the following..

public void reset(){

         this.number = 0;

     }
Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
  • Same issue here: All `Counter` objects will live forever, since the garbage collector will think that they are used through the `counters` collection. – krlmlr Jul 09 '12 at 19:04
  • use are resetting the objects, not making them ready for the garbage collection..right...!! – Kumar Vivek Mitra Jul 09 '12 at 19:06
  • Right. But same as above: Consider a counter that has been `.add()`ed to the `counters` but has no other reference pointing to it. It is essentially dead, but still will be `reset`. Does this make sense to you? – krlmlr Jul 09 '12 at 19:27
  • then use c.remove(); actually its not mentioned in your question, else writing another 1 line wont matter.(here c.remove()) – Kumar Vivek Mitra Jul 10 '12 at 03:05
  • 1
    You don't always have (or want to have) manual control over the lifetime of your objects, that's what the garbage collector does in the first place. – krlmlr Jul 10 '12 at 06:38
  • Yes offcourse we dont have any control over the lifetime of the objects, but you can use gc method to atleast suggest it to end the lifetime of the object, thought its entirely upon the Garbage collector to do it.. – Kumar Vivek Mitra Jul 10 '12 at 07:05
  • No you can't, because the objects are held by the collection `arr` using a strong reference. **They never die.** I have posted two links in the first part of my answer, you might want to read them. – krlmlr Jul 10 '12 at 07:29
  • Tell me one thing..is your problem of resetting the objects value is answered by my answer ? – Kumar Vivek Mitra Jul 10 '12 at 08:52
  • 1
    Please tell me another thing first. Do you mind if an application, say, a service that is not intended to be restarted, leaks memory -- the longer it runs, the more memory it consumes, finally taking down the whole system? – krlmlr Jul 10 '12 at 09:11
  • Kumar It seems you may not have noticed, @user946850 is not the question asker. – Nicole Jul 11 '12 at 17:35