Home > Mobile >  NOT wanting to call the default constructor from child class
NOT wanting to call the default constructor from child class

Time:07-19

I am working on an animal class which needs a default constructor. I also need to extend the animal class with specific animals as well, with their own names and sounds.

My Animal class is as follows:

public class Animal {

public String name;
public String sound;

public Animal() {
    this.name = "animal";
    this.sound = "an animal makes a sound based on what animal that it is";
    System.out.println("I am an animal");
}
        
public void sound() {
    System.out.println("The "   name   " says "   sound);
}

After I wrote the other animal classes such as Sheep, pig and cow, I wrote a test class to verify if it was working. They're carbon copies basically but here is the first one I wrote, the cow class:

public class Cow extends Animal {
public String name = "Cow";
public String sound = "Moo";


public Cow() {
    System.out.println("I am a cow");
}
 

public void sound () {
    System.out.println("The "   name   " says "   sound);
}
    

}

My issue is that after making new "cows", or any of the other animals they all start out by saying "I am an animal" which is from the default constructor within the animal class and not needed. How can I avoid this? I was under the impression the default constructor would only be called when creating a new animal via Animal animal1 = new Animal(); but clearly, that is not the case.

I've been reading my textbook, looking over YouTube as well as here on Stack but to no avail.

Thought maybe I had to override something but I am not sure.

Here is my Test class and output:

public class Test {

public static void main(String[] args) {
    Animal animal = new Animal();
    animal.sound();
    Cow cow = new Cow();
    cow.sound();
                
}

}

Output:

I am an animal
The animal says an animal makes a sound based on what animal that it is
I am an animal
I am a cow
The Cow says Moo

Because I am actively trying to learn java I would very much appreciate being guided towards an answer, as well as an explanation to help me understand why this is happening.

CodePudding user response:

The question why the superclass constructor is called, even without explicit super(); call is answered here. One of the constructors of the superclass must always be called. If the superclass has a (possibly implicit) default constructor then the super(); call from the subclass can be omitted, but the constructor is called implicitly. Your Cow constructor is the same as this one:

public Cow() {
    // Calls the `Animal()` superclass constructor
    super();
    System.out.println("I am a cow");
}

In your specific situation it might make sense to add an additional Animal constructor which takes the name and sound values as parameters and initializes the fields. If you still need a default Animal() constructor, you can have that delegate to the other constructor:

class Animal {
    public String name;
    public String sound;

    public Animal(String name, String sound) {
        // `this.name` refers to the field, `name` refers to the parameter
        this.name = name;
        this.sound = sound;
    }

    public Animal() {
        // Uses `this(...)` to call the other constructor
        this(
            "animal",
            "an animal makes a sound based on what animal that it is"
        );
        System.out.println("I am an animal");
    }

    ...
}

Note: If you don't expect these fields to be reassigned, then you should make them final to protect against bugs and for thread-safety improvements.

Your subclasses can then call the Animal(String, String) constructor:

public class Cow extends Animal {
    public Cow() {
        // Calls the `Animal(String, String)` superclass constructor
        super("Cow", "Moo");
    }
}

This does not declare additional name and sound fields because the ones from Animal are inherited and accessible to Cow. Your current code for Cow actually introduces additional fields which hide the ones from Animal, see this answer.

CodePudding user response:

What You Can Do in a Subclass

A subclass inherits all of the public and protected members of its parent, no matter what package the subclass is in. If the subclass is in the same package as its parent, it also inherits the package-private members of the parent. You can use the inherited members as is, replace them, hide them, or supplement them with new members:

  • The inherited fields can be used directly, just like any other fields.
  • You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it (not recommended).
  • You can declare new fields in the subclass that are not in the superclass.
  • The inherited methods can be used directly as they are.
  • You can write a new instance method in the subclass that has the same signature as the one in the superclass, thus overriding it.
  • You can write a new static method in the subclass that has the same signature as the one in the superclass, thus hiding it.
  • You can declare new methods in the subclass that are not in the superclass.
  • You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword super.
  • Related