I will try to describe what happens in the background, in the hopes that it will clear some things.
Lets break this declaration & definition into parts.
- 'a' is declared as an Animal.
- 'a' is defined as a Dog.
- Dog extends Animal, therefore, animal methods (including constructor) get defined.
- Dog's methods get defined, whilst overriding any method that was defined by the parent class Animal) and overshadowing member variables of the parent class.
When looking at 'a', you are using the 'Animal' perspective and for that reason you are not capable of using any methods (or fields) declared only by sub-classes of Animal. In order to "gain" that perspective you can downcast from Animal to Dog exactly as you did. Keep in mind that downcasting is not safe whereas upcasting is.
For example:
Animal a = new Cat(); // cats can mew
Animal b = new Dog(); // dogs can bark
(Dog)b.bark() // Unsafe but compiles and works.
(Dog)a.bark() // Unsafe but compiles and throws a run time exception.
In general, a good practice would be to create an abstract class for an Animal and then override some of it's methods with subclasses.
For example:
public abstract class Animal {
abstract void makeNoise();
}
public class Dog extends Animal {
void makeNoise(){
System.out.println("bark");
}
}
public class Cat extends Animal {
void makeNoise(){
System.out.println("mew");
}
}