In your constructor, when you say
int age = dogsAge; you're declaring a separate
age variable. It's separate because you used the keyword
int to denote that it's a new integer. And the reason why the names don't clash is because they're not declared in the same scope as one another.
Scope, if you're unsure, just means where the methods and variables reside in relation to each other. Eg,
Class Dog is the main scope where everything inside of it is sort of like a family.
Int age can be accessed anywhere because it is declared at the class level.
public void bark() is a scope of its own. It's part of the class
dog but inside of the
bark(), variables that are declared are only available to use inside that scope. Other methods like
getAge() will not have access to these variables unless you pass it in a method call parameter or move the variable to the outer class Dog scope for everyone to have access to.
So because they are separate the age declared in the constructor is set to 5 and shortly after is destroyed because nothing is actually done with the variable.
The class level variable is declared as
int age;. Declaring variables without defining their values explicitly ie not
int age = 1; will assign that variable a default value automatically. So
int age; Will essentially be equal to 0.
And because whatever is in the constructor is not reflected in the class age variable that is why when you call spike.getAge() you're getting 0.
Hope that clears it up.