0

I was working on a game recently in C++ where I implemented the Command Pattern to manage keyboard input to control a spaceship. When instantiating all the commands, I'd pass the spaceship pointer to each constructor so all commands were working with the same spaceship object.

This pattern made sense in C++ because you can pass by reference, but in Java everything is pass-by-value. If I tried to implement the same thing in Java, how would I have each command pointing to the same object?

In all the examples I've seen of the Command Pattern used in Java it makes no difference whether the member variables of each Command are copies or references.

pjivers
  • 1,283
  • 12
  • 20
  • 5
    who did tell you that Java passes parameters by value?? – vulkanino Feb 15 '12 at 11:01
  • 4
    @vulkanino: Someone who was correct. Java passes references by-value (see e.g. http://stackoverflow.com/questions/40480/is-java-pass-by-reference). – Oliver Charlesworth Feb 15 '12 at 11:03
  • That I know, Java always passes by reference. – kist Feb 15 '12 at 11:04
  • 3
    @kist: Java never passes by reference. – Oliver Charlesworth Feb 15 '12 at 11:04
  • @OliCharlesworth non entirely. a reference type (class) is passed as a formal parameter to a method by value (the **reference** is passed by value), and by reference (a reference to the "pointed" class). you can't change the reference but you can mutate the value (using setters for example). – vulkanino Feb 15 '12 at 11:06
  • 3
    @vulkanino So OliCharlesworth is right. Java **always** passes by value. It also passes references by value. Note that passing a reference by value is not the same as passing by reference. – Jesper Feb 15 '12 at 11:08
  • anyhow the command pattern makes perfectly sense in java too. the command classes that implement Command will store a reference to the type he wants to control. – vulkanino Feb 15 '12 at 11:09

4 Answers4

2

Java does pass by value in all cases, however all 'non-primitive' types exist as references, so for types like String, List or Spaceship you're actually passing a reference around - the pass by value is because you're passing the reference by value. Which is a pretty confusing way of expressing it, I always felt.

Anyway, the upshot of it is that if you have a (hugely simplified) Command class

public class Command {
    private Spaceship spaceship;
    public Command(Spaceship ship) {
        spaceship = ship;
    }
}

And then you do this:

Spaceship ship = new Spaceship();
List<Command> ships = new List<Command>();
for (int i = 0; i < 40; i++) {
    ships.add(new Command(ship));
}

then every single one of those Command objects has a reference to the same Spaceship object. Passing the reference by value does not cause a copy of the Spaceship object that the reference points to. However, if you were passing ints around, you would indeed be passing copies.

Just remember the distinction between primitive types like int, and object types like String and you'll be fine. It's helpful to remember that primitive type names begin with a lowercase letter (and can never be user-defined), while object types begin with a capital letter. All user-defined types are object types.

Matthew Walton
  • 9,322
  • 3
  • 25
  • 36
  • this is exactly what I was trying to say :) – vulkanino Feb 15 '12 at 11:13
  • Indeed. I just felt it needed more explanation because 'it always passes by value but for objects it's passing references' might be a bit too concise for a new Java programmer to fully understand. – Matthew Walton Feb 15 '12 at 11:16
  • @MatthewWalton Slightly off the point, but in your code you are adding Commands to a List of Spaceships. Should probably be a List of Commands? – DaveJohnston Feb 15 '12 at 11:28
  • @DaveJohnston You're correct, it should have been. Fixed it, thanks for pointing it out. – Matthew Walton Feb 15 '12 at 11:30
1

Thanks for your help guys. At the end of the day it came down to my complete misunderstanding about how Java works. I was under the impression (for some strange reason) that creating a Command and giving it my object meant that it received a copy instead of a reference to the original. If that was the case then calling .execute() in a Command would have had no effect on the object outside of the class.

Yet, I found that this was not the case after creating a small test:

Sprite.java:

public class Sprite {
    private int x;

    Sprite(int x) {
        this.x = x;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }
}

Command.java:

public interface Command {
    void execute();
}

MoveLeftCommand.java:

public class MoveLeftCommand implements Command {
    private Sprite s;

    MoveLeftCommand(Sprite s) {
        this.s = s;
    }

    public void execute() {
        s.setX(s.getX() - 1);
    }
}

MoveRightCommand.java:

public class MoveRightCommand implements Command {
    private Sprite s;

    MoveRightCommand(Sprite s) {
        this.s = s;
    }

    public void execute() {
        s.setX(s.getX() + 1);
    }
}

Test.java:

import java.lang.*;
import java.util.*;

public class Test
{    
    public static void main(String[] args) {
        Sprite mario = new Sprite(0);
        Command command = null;

        Map<String, Command> commands = new HashMap<String, Command>();
        commands.put("a", new MoveLeftCommand(mario));
        commands.put("d", new MoveRightCommand(mario));

        // Test...
        System.out.println(mario.getX()); // 0

        command = (Command) commands.get("a");

        command.execute();
        System.out.println(mario.getX()); // -1
        command.execute();
        System.out.println(mario.getX()); // -2

        command = (Command) commands.get("d");

        command.execute();
        System.out.println(mario.getX()); // -1
    }
}

I correctly saw 0 -1 -2 -1 in the console, just as I would have in C++.

pjivers
  • 1,283
  • 12
  • 20
0

In java they passed "by value"... You pass real object that will implement an execute method. Sharing reference among different objects can be achieved by proper OO design or lookup method injection for common attribute. The Command pattern example was taken from wikipedia

/*the Command interface*/
public interface Command {
   void execute();
}


/*the Invoker class*/
import java.util.List;
import java.util.ArrayList;

public class Switch {

   private List<Command> history = new ArrayList<Command>();

   public Switch() {
    }

   public void storeAndExecute(Command cmd) {
      this.history.add(cmd); // optional 
      cmd.execute();        
   }

}


/*the Receiver class*/
public class Light {

   public Light() {
   }

   public void turnOn() {
      System.out.println("The light is on");
   }

   public void turnOff() {
      System.out.println("The light is off");
   }

}


/*the Command for turning on the light - ConcreteCommand #1*/
public class FlipUpCommand implements Command {

   private Light theLight;

   public FlipUpCommand(Light light) {
      this.theLight = light;
   }

   public void execute(){
      theLight.turnOn();
   }

}


 }
Buhake Sindi
  • 82,658
  • 26
  • 157
  • 220
aviad
  • 7,675
  • 9
  • 43
  • 90
0

Since Java always does pass by value, you will need to do something mutable to pass through instead (pass a mutable object).

Consider this example:

In this agnostic language that supports pass-by-reference

string commandArg = "";
new StringCommand().execute(commandArg);
Console.write(commandArg);

And in StringCommand.execute(string arg), you have arg += "Hello World", then your output will be Hello World.

In Java, simply pass a StringBuilder as follows:

StringBuilder sb = new StringBuilder();
new StringCommand().execute(sb);
System.out.println(sb.toString());

where StringCommand.execute(StringBuilder sb) contains:

sb.append("Hello World");

The StringBuilder reference is passed by value in StringCommand.execute. In a nutshell, primitive types are passed by value and, for objects, the reference of the object is passed by value.

I hope this helps.

Buhake Sindi
  • 82,658
  • 26
  • 157
  • 220