3

I have following main class and main method:

public class Main {

Peter peter = new Peter(this);
Tom tom = new Tom(this);

    public static void main(String[] args) {
        Main main = new Main();
        System.out.println(main.peter.tom);
        System.out.println(main.tom.peter);
    }
}

and the following Parent class:

class Enemy {
     //some variables
}

and following two child classes:

class Tom extends Enemy {

    Enemy peter;

    Tom(Main main) {
        this.peter = main.peter;
    }
}

class Peter extends Enemy {

    Enemy tom;

    Peter(Main main) {
        this.tom = main.tom;
    }
}

When the two print methods run in the main method, the first one returns a null, because the Tom wasn't created at the time it is assigned to Enemy tom. To solve this, I didn't assign Tom and Peter to Enemy in the constructor but rather with a method after the creation of the two objects. So more like this:

private void setEnemies(){
    peter.tom = tom;
    tom.peter = peter;
}

When the method is called before the println methods, it works flawlessly. My question is: Is there a way to set the enemies at object creation so I don't have to call a separate method after the objects are created?

Stefan B
  • 541
  • 2
  • 6
  • 13
  • 1
    Note that the problem you describe is because `Peter peter = new Peter(this);` is an example of *unsafe publication*: you are passing the `Main` reference to the constructor of `Peter` before `Main` is fully initialized. This means that `Peter` can start doing things with the `Main` before it is in a valid state, so unexpected and unpredictable before can result. – Andy Turner Aug 04 '16 at 09:44
  • I know in my current project i create `Peter` and `Tom` from a constructor of another class. I posted it this way to simplify the code. – Stefan B Aug 04 '16 at 09:46
  • The same thing is done for `RadioButton`s with a single `RadioButtonGroup` added to their construction / being a factory. Then the RadioButtonGroup ensures that all radio buttons relate to each other, – Joop Eggen Aug 04 '16 at 10:11

4 Answers4

7

The short answer is: no, you can't. The reason is that you have to create these instances one at a time; and when you create the first one, the second one doesn't yet exist, so can't be passed to the first one.

It shouldn't be a terrible restriction, though. You want to add a void setEnemy(Enemy myEnemy) method to the Enemy class, and then call it for each of your enemies. Something like this:

Enemy peter = new Peter();
Enemy tom = new Tom();
peter.setEnemy(tom);
tom.setEnemy(peter);
chiastic-security
  • 20,430
  • 4
  • 39
  • 67
2

In general refering to an object that still does not exist can only be done in a not yet evaluated function. Here java 8 can come to help.

Enemy peter = new Enemy(() -> tom);
Enemy tom = new Enemy(() -> peter);


public class Enemy {

    private final Supplier<Enemy> enemySupplier;

    public Enemy(Supplier<Enemy> enemySupplier) {
        this.enemySupplier = enemySupplier;
    }

    public Enemy enemy() {
        return enemySupplier.get();
    }

Of course between the declaration of peter and tom, peter's enemySupplier too would return null, but that is guaranteed by the code. If the constructor still does not do anything with its enemy.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
2

You can use a Domain driven design approach. I've made your example a bit more generic to show you how it works.

class Enemy {
    Enemy enemy;

    public Enemy createEnemy() {
        Enemy enemy = new Enemy();
        enemy.enemy = this;
        this.enemy = enemy;
    }
}

class Peter extends Enemy { }
class Tom extends Enemy { }

You would then use it like so:

Peter peter = new Enemy();
Tom tom = peter.createEnemy();
System.out.println(peter.enemy); // returns Tom
System.out.println(tom.enemy); // returns Peter
James Monger
  • 10,181
  • 7
  • 62
  • 98
1

You cannot set them at object creation because you create the objects (Peter and Tom) one after the other. And when creating the first one the second one still isn't instanced. This way you cannot pass the second one (which is not yet created) to the first one. If you create it like Enemy peter=new Peter(); it will be different instance of the peter object so it still won't be what you want

Veselin Davidov
  • 7,031
  • 1
  • 15
  • 23