0

I create a method that casts an aging spell upon people and decreses their age by two:

public class Wizard {

    void agingSpell (Person x) {
         x = new Person(x.age);
         x.age -=2;
    }
}

Here's the class describing those people:

 public class Person {

     int age;
     int weight = 90;
     String name = Max;

     Person (int x){
     this.age = x;
     }
 }

I create an instance of Person and Wizard:

 Person max = new Person(26);
 Wizard albus = new Wizard();

Then, I call the method agingSpell and source max as its argument:

 albus.agingSpell(Person max);

Then, as I see it, the reference value inside max is assigned to x inside the method:

Person x = max;

Now we have one more reference to the created object. Next, a new object is created and (again, I might be wrong), is saved inside the x:

      x = new Person(x.age)

I understand the old object to be substituted by the new one, so there has to be no trace of the old one inside the method. BUT, if I compile the code the age of the new object would also be 26 . Furthermor, I can easily access all the other fields of the older object (which was supposed to be unaccessible the moment we assigned his x reference to another object). I know I'm definitely missing something. Could you, please, help me figure it out?

Here's the executing portion of the code:

public class Wizard {

}

public static void main (String [] args){
    Wizard albus = new Wizard();
    Person max = new Person(26);
    albus.agingSpell(max);
    System.out.println(max.age);
}

}

  • [relevant](https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value) – Green Cloak Guy Feb 13 '20 at 20:03
  • Shouldn't an "aging spell" _increase_ someone's age? – Nexevis Feb 13 '20 at 20:11
  • Oh, it was just a piece of a made-up code to understand why ```x.age = 26```, when it should be ```x.age = null```, since it is referencing the new object. It's not actually built to make someone two years younger:) – Vsevolod IV Feb 13 '20 at 20:16

2 Answers2

2

You reassign x in the spell method, so it points to the new person, then you change that new person's age, and then you throw that person away. So the net result is nothing changed. It's the same as doing this:

void agingSpell(Person p) {
  Person throwaway = new Person(p.age);
  throwaway.age -= 2;
  // when this method returns, "throwaway" literally gets thrown away.
}

A better question is "why are you generating a new person at all, if the intent is to decrease a person's age?". Have the spell directly update the person you pass in:

class Wizard {
  final int DEFAULT_AGE_DECREASE = 2;

  ...

  void agingSpell(Person p) {
    this.agePerson(p, DEFAULT_AGE_DECREASE);
  }

  void agingSpell(Person p, int years) {
    // let's keep a person's age a protected field
    p.setAge(p.age - years);

    // and you'll probably need logic for age hitting/dropping below zero
  }

  ...
}
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • You said: "then you changed that new person's age". This is exactly what I don't understand. Why is the new person's age = 26 and not "null"? If we load the object reference into the method, "p.age" = 26. Why? – Vsevolod IV Feb 13 '20 at 20:27
  • Look at your constructor for `Person`. It takes an int and assigns that to the `age` field for the instance that it's constructing. So if you have `Person bob = new Person(26)`, and then you do `Person carol = new Person(bob.age)`, that is exactly the same as `Person carol = new Person(26)`, with the Person object that `carol` points to having an `age` field that has the int value 26, because that's the only thing your code allows to happen. You don't have a constructor for `Person` that leaves `age` unassigned. – Mike 'Pomax' Kamermans Feb 13 '20 at 20:33
  • Uhum, so before the old object is trown away, we pass its "age" parameter on to the new one, right? I think I just have a misconception of how creation of new objects happens. Here's how I see it: "Person x = (A) new Person (x.age) (B)": I thought that the old object is getting discarded at the poin (A), but it seems, in fact, to live up to the point (B), where the new object is initialized. I'm sorry, I'm new to Java, and thank you for your help, time and effort!:) – Vsevolod IV Feb 13 '20 at 21:12
  • The old one is _never_ thrown away. In your code, you make and then immediately throw away the _new_ person. In your method `agingSpell` the variable `x` is scoped _to that method_ so reassigning it does only that: it makes the alias `x` point from whatever it was pointing to before, to whatever you assigned to it now. Nothing happens to that thing it pointed to before during that assignment. It still exists for any code _outside_ your method. This is part of the basics of Java, so you definitely want to read through the link that Green Cloak Guy gave you in their comment. – Mike 'Pomax' Kamermans Feb 13 '20 at 21:13
1

Define agingSpell as follows:

void agingSpell(Person x) {
    x.age -= 2;
}

-OR-

Return the new object you are creating. Note that the scope of the new object you are creating inside agingSpell is limited to this method only i.e. as soon as the control comes out this function, the new object will cease to exist.

class Wizard {

    Person agingSpell(Person x) {
        x = new Person(x.age);
        x.age -= 2;
        return x;
    }
}

class Person {

    int age;
    int weight = 90;
    String name;

    Person(int x) {
        this.age = x;
    }
}

public class Main {
    public static void main(String[] args) {
        Wizard albus = new Wizard();
        Person max = new Person(26);
        System.out.println(albus.agingSpell(max).age);
    }
}
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110