chharvey
chharvey

Reputation: 9376

Destroying objects in Java

I have a general idea of how the Garbage Collector works in Java, but my reasoning for destroying an object is not because I care about freeing up memory, but because of functionality. I can explain better with an example:

Say I'm making a game where money is involved. When a person picks up a Money object off the ground, I want to call that object's addTo method, which involves adding a value to that person's wallet.

public class Money {

  /** The value of this object. */
  private final int value;

  // constructor
  public Money(double x) {
    this.value = x;
  }

  // Should be called when a Person picks up this object.
  public void addTo(Person bob) {
    bob.addToWallet(this.value);
  }

  // MAIN METHOD
  public static void main(String[] args) {
    Person bob = new Person();
    Money dollar = new Money(1.00);
    dollar.addTo(bob);    // bob finds $1.00
  }
}

After dollar is found, I don't want someone else to be able to pick it up. In other words, I don't want myself or any other program to be able to accidentally call the line:

dollar.addTo(alice);

So after Bob picks up the money, its value is added to his wallet and there's no need for an object representation of that value anymore. It's not that I care about the memory the object is using, but I don't want that object to be accidentally used somewhere else in the program. How do I destroy dollar besides setting dollar = null;?

Upvotes: 2

Views: 1051

Answers (8)

Alexander Malakhov
Alexander Malakhov

Reputation: 3529

Though defining ownership (ground with collection of Moneys, wallet as collection, or owner attribute for money) could be theoretically cleaner solution, I can easily imagine situation when this is overkill.

For example, it could be completely irrelevant where person have taken his money. And once money have been taken the game don't care who posses that instance of Money

I suggest to simply add isPicked attribute:

public class Money {

  private final int value;
  private boolean _isPicked = false;

  public Money(double x) {
    this.value = x;
  }

  public boolean isPicked(){
    return _isPicked;
  }

  public void addTo(Person bob) {
    if( this.isPicked )
        throw new Exception("some message for developers");

    bob.addToWallet(this.value);
    _isPicked = true;
  }

  public static void main(String[] args) {
    Person bob = new Person();
    Money dollar = new Money(1.00);
    dollar.addTo(bob);    // bob finds $1.00
    // dollar = null;     // don't need this anymore

    Person alice = new Person();
    dollar.addTo( alice ); // <------   RUNTIME EXCEPTION
  }
}

Doing dollar = null will result in exception too, but it's less safe, because you can simply forget to do it, or accidentally copy reference to another variable

Upvotes: 0

Marsellus Wallace
Marsellus Wallace

Reputation: 18611

You have NO CONTROL over Java Garbage Collection -GC- and there is now way that you can force the Java Virtual Machine to destroy an object for you.

You can call System.gc() [or Runtime.getRuntime().gc()] but that only suggests the JVM to run the Garbage Collection. The true is that the JVM is not supposed to listen to you for this and the GC execution is not guaranteed. Do not rely on that.

Regarding your design need, put your money in a bank (or a street if you want people to find them) and ask the bank to give you one. Assuming that the bank has only 1, then subsequent calls will return null.

EDIT AFTER DOWNVOTE

I decided to remove some dust from my books and to quote a few lines from the Forcing Garbage Collection section of the 3rd chapter of the SCJP Study Guide. A book that I studied for pure masochism.

The first thing that should be mentioned here is that, contrary to this section's title, garbage collection cannot be forced.

..it's recommended that you never invoke System.gc() in your code - leave it to the JVM.

..it is only possible to suggest to the JVM that it performs garbage collection. However, there are no guarantees the JVM will actually remove all of the unused objects from memory (even if garbage collection is run).

Garbage Collection is a harder concept than it seems...

Upvotes: 1

Dilum Ranatunga
Dilum Ranatunga

Reputation: 13374

As an extension to what @pstanton said, keep collections of owned objects. Here's an elaborate way, which is useful for preventing mistaken code from corrupting your state.

public abstract class Possession {
  private Object _key = null;

  public synchronized Object acquire() {
    if (_key != null) { throw new IllegalStateException(); }
    _key = new Object();
  }

  public synchronized void release(Object key) {
    if (_key != key) { throw new IllegalStateException(); }
    _key = null;
  }
}

public class Possessions implements Iterable<Possession> {
  private final Map<Possession, Object> _possessions = new IdentityHashMap<...>();

  public synchronized void add(Possession p) {
    if (!_possessions.containsKey(p)) {
      _possessions.put(p, p.acquire());
    }
  }

  public synchronized void remove(Possession p) {
    Object key = _possessions.remove(p);
    if (key != null) {
      p.release(key);
    }
  }

  public Iterator<Possession> iterator() {
    return Collections.unmodifiableSet(_possessions.keySet()).iterator();
  }
}

public class Money extends Possession { ... }

public class Person {
  private final Possessions _possessions = new Possessions();

  public void add(Money money) {
    _possessions.add(money);
  }
}

Upvotes: 1

pstanton
pstanton

Reputation: 36689

You shouldn't be thinking of garbage collection at all. It is up to the JVM to determine when things can be garbage collected and 99% of the time, you won't need to consider this at all if you program responsibly.

Answer me this .. how would "the object be accidentally used somewhere else in the program"?

The answer is, it couldn't. A local reference exists until the end of your main method and no longer. Unless you store a reference to it, it cannot be referenced.

As your program grows, it might be a good idea to store a reference to it temporarily. You need to represent your concept of "the ground" with an object. Since the functionality you describe is basic, you can just use any of the built in implementations of Collection for example List.

List<Money> floorMoney = new LinkedList<Money>();
floorMoney.add(new Money(1.00));

and when you associate money from the floor with a Person you would remove it from the floor.

Money dollar = floorMoney.get(0); // how you access elements may vary
floorMoney.remove(dollar);
dollar.addTo(bob);

Now, unless you store a reference to dollar somewhere in your addTo implementation, the Money object will be abandoned and later GC'd.

Upvotes: 3

Paul
Paul

Reputation: 20091

dollar=null will do the trick. By eliminating the reference to that object, the object cannot be referenced. The garbage collector is not relevant here.

Think about it this way: if you don't want someone to come to your house, you don't have to blow up your house. Just don't give them the address. Fortunately Objects can't stalk other Objects like a crazed ex-girlfriend can stalk the guy who dumped her...parking outside his work, sending texts at all hours, calling his parents...

Oh, sorry, back to your question.

If the ground is a Collection of some sort (e.g. a List) then removing that money from your ground collection will also keep it out of the reach of other players or rogue sentient Objects.

And if your money is also an Object with a value, after picking the first player picks it up you could set its value to -1000, thus punishing the players who would take something that is clearly not theirs.

Upvotes: 1

mkk
mkk

Reputation: 7693

why you cannot add a boolean "picked" default = false? or create a list and remove from it?

Upvotes: 0

seand
seand

Reputation: 5296

You simply have to avoid making 'dollar' available to places you don't want it to go. Note that this isn't really a GC issue. For a non-GC environment (like C++) someone who somehow sees a pointer to an deleted object will crash and burn if they try accessing it.

Upvotes: 0

RAY
RAY

Reputation: 7110

If you are really trying to model the real world as closely as possible, you could add a owner attribute to the dollar, so that when you call dollar.addTo(), you will have to change the owner, the dollar only belongs to one person at any given time.

Upvotes: 3

Related Questions