0

I'm fairly new to Java and still practicing by basics with object-oriented design and programming. I have a few questions regarding inheritance, object creation, and the correct usage of a super() call.

Please consider the following:

Superclass,

package pet

public class Dog {

    private String foodDogEats;

    public Dog() {
        this.foodDogEats;
    }

    public String getDogFood() {
        return foodDogEats;
    }

    public void setDogFood() {
        foodDogEats = "kibble";
    }

}

subclass,

package pet

public class Fido extends Dog {

    public Fido() {
        super();
        Dog dog = New Dog();
        this.whatDoesFidoEat();
    }

    public whatDoesFidoEat(Dog dog) {
        System.out.println("Fido eats " + dog.getDogFood());
    }

}

and controller.

package pet

public class MyDogFido {

    public void MyDogFido() {
        Fido fido = new Fido();
    }

}

The object in this example is, to instantiate a new Fido object and in the process of doing so perform the print behavior in whatDoesFidoEat(). I have a few questions -

Since I am already invoking a new Fido object (which is an extension of Dog, and if I recall correctly inherits its methods and variables), is instantiation of a new Dog object in the Fido() constructor redundant?

What about use of super()?

Which is the correct behavior - instantiating a Dog object in Fido(), calling super(), or both?

I initially wrote some similar code using both in the controlling class. After writing this question, though, my gut is telling me that I should only call super().

Feel free to comment on my sample code (particularly the this.foodDogEats; line in the Dog() constructor - also unsure about the usage there) as well.

Thanks!

drs
  • 35
  • 6
  • One thing to note is that if the superclass uses `private` data members, they can only be accessed using the get/set methods of the superclass. You can use `protected` to allow sublcasses direct access to the data members via `this`. Often `private` is still used in cases where some logic happens in the get/set methods that is required for proper function of the superclass. – RayfenWindspear Jul 19 '16 at 18:49
  • This isn't related to the question exactly, but it's a good idea to avoid calling non-final methods from your constructor (as you did in the `Fido()` constructor). If you subclassed `Fido` and overrode the `getDogFood()` method you could end up with some very unexpected behaviour. – Sam Jul 19 '16 at 18:50

5 Answers5

7

You're right that the Dog dog = new Dog(); line is redundant. It would create a second, entirely separate Dog object.

The super() call is also unnecessary. All Java constructors implicitly call super() unless you override that behaviour by calling a different super-constructor.

Sam
  • 8,330
  • 2
  • 26
  • 51
  • Thanks for the clarification! So basically neither - when I create a Fido object, it does everything for me then? What about setting of the superclass variable(s)? Do I need make a call to the superclass setter method? Can I skip that if call it in superclass constructor? If so, is it an acceptable practice to do so? – drs Jul 19 '16 at 18:52
  • If the superclass has private variables it has to set them itself. If the subclass wants to set those values at construction time you can pass them as arguments to a super constructor. – Sam Jul 19 '16 at 18:56
  • Would it be better practice to make all variables in a superclass private for the purpose of encapsulation? – drs Jul 19 '16 at 18:57
  • See http://stackoverflow.com/questions/27431373/why-do-we-declare-private-fields-when-we-have-accessors-and-mutators and/or http://programmers.stackexchange.com/questions/143736/why-do-we-need-private-variables – Sam Jul 19 '16 at 18:59
2

Since I am already invoking a new Fido object (which is an extension of Dog, and if I recall correctly inherits its methods and variables), is instantiation of a new Dog object in the Fido() constructor redundant?

It is not redundant per se, but it is rather pointless and wasteful. You are instantiating a new, different Dog, and then ignoring it. The garbage collector will eventually clean it up, but you never needed it in the first place. Your Fido, which you can refer to inside the class constructor and methods as this, is a Dog. You do not need to do anything in the constructor to make that be so, and you cannot do anything in the constructor to prevent it from being so.

What about use of super()?

If a class's constructor does not explicitly invoke either another constructor of the same class or one of the superclass's constructors, then it implicitly invokes super(). In that case, if the superclass has no such nullary constructor then that is an error. It is not exactly redundant to explicitly invoke super() because that suppresses the implicit invocation, but it is not necessary to do so.

Which is the correct behavior - instantiating a Dog object in Fido(), calling super(), or both?

You initialize the superclass by directly or indirectly invoking one of its constructors. That invocation can be implicit if the superclass has a nullary constructor, and if that's the one you want to invoke.

Feel free to comment on my sample code (particularly the this.foodDogEats; line in the Dog() constructor - also unsure about the usage there) as well.

The line you reference is erroneous. If it were allowed, I would expect it to evaluate to the default value of this.foodDogEats (null), with no other effect. That would be pretty pointless.

Additionally, your setDogFood() method is odd. A property setter would normally have this form:

    public void setDogFood(String what) {
        foodDogEats = what;
    }

Your original version is kinda pointless.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Thanks for the clarifications! Regarding `setDogFood()` - in the instance that the variable is predetermined and unchanging, would it be better to declare that variable's value in the `Dog()` constructor? What about setting it in `Dog` class code block? If I set it in the code block, how should I keyword it in order to encapsulate properly while retaining subclass access? – drs Jul 19 '16 at 19:02
  • @drs, you can avoid providing a means to change `Dog`'s food, but you cannot make it genuinely unchanging while allowing it to be variable in subclasses. In any event, the method you provided is nowhere invoked in your code; it has no effect unless invoked. If a value different from `null` is desired in new instances then it is the constructor's job to set that value. Perhaps you want a constructor that accepts the appropriate food as a parameter. – John Bollinger Jul 19 '16 at 19:06
1

your code should show a compiler error in the superclass.

Let's run through the logic you have:

In the super class you have

this.foodDogEats; // should be a compiler error

What do you think it does? It does nothing because it is just a statement. The 'this' keyword only means you are referring to the variable in the specific instance of the object that you created but you do nothing with it which leads to the error.

In your subclass, you do not need to call super since super is called automatically by default unless you do not have a no argument constructor in the super class.

ucsunil
  • 7,378
  • 1
  • 27
  • 32
  • Thanks for the clarification! I take it only need to worry about using `this` when I've created a new object of that class in a different class, and wish to reference that specific variable? – drs Jul 19 '16 at 18:47
  • You need to bother with the 'this' keyword only when you are using inheritance and when you have a variable, object or method in that class which also exists in the superclass (meaning they have the same name). The 'this' keyword lets the run time know that you mean to use the instance defined in the subclass and not the one defined in the superclass. Else there will be clash when same names are used. – ucsunil Jul 19 '16 at 18:52
  • In that instance, should `this` be used in the subclass constructor? – drs Jul 19 '16 at 19:13
  • You don't need 'this' in your subclass either in this specific case since you do not have any name clashes as far as I can see but if you do have such a clash, then you should use it – ucsunil Jul 19 '16 at 19:44
1

Your use of super() is correct. Your use of a Dog object is completely unnecessary.

By extending Dog, Fido inherits the non-private fields and method of Dog. Therefore, you can simplify Fido:

package pet;

public class Fido extends Dog {

    //Since this is a default constructor (no args and super() only),
    //you don't even have to declare this.
    public Fido() {
        super();
    }

    public void whatDoesFidoEat() {
        System.out.println("Fido eats " + foodDogEats);
    }

}

And then, simplify your use of it:

package pet;

public class MyDogFido {

    public void MyDogFido() {
        Fido fido = new Fido();
        //This is a setter method for your foodDogEats. It should be declared in Dog.
        fido.setFoodDogEats("Beggin' Strips");
        fido.whatDoesFidoEat();
    }

}

You can still have your Fido() constructor call whatDoesFidoEat, but since creation of the object doesn't seem dependent on the method, I find it better practice to avoid calls like that in the constructor.

Edit:

If you wanted to define foodDogEats upon construction, you could define a constructor Fido(String):

public Fido(String foodDogEats) {
    this.foodDogEats = foodDogEats;
}

Or if your foodDogEats is dependent on the class rather than the instance, and never changes, you could make the variable public static final FOOD_DOG_EATS. Be careful - accessing it via Fido.FOOD_DOG_EATS will be different than Dog.FOOD_DOG_EATS because static variables are not inherited.

Zircon
  • 4,677
  • 15
  • 32
  • Thanks for the clarification! So in general, you don't think I should call setter methods in the constructor? What about in a specific usage such as this, where the variable `foodDogEats` is predetermined to have a static value? If it is predetermined and will not change, should I even bother having a setter instead of setting the value in the constructor (or beforehand with `public static final` in the class code block)? – drs Jul 19 '16 at 18:55
  • You're on the right track, but it depends on the scenario as well. I will elaborate in an edit. – Zircon Jul 19 '16 at 19:03
  • Hmm.. In the event that I need a subclass to inherit a static (read: unchanging) value, would it be best to have the superclass constructor set this value? – drs Jul 19 '16 at 19:26
  • "static (read: unchanging)" - `final` is non-changing. `static` is something associated with the class, not an object (could be read: "consistent"?). If you choose to have a `static` variable, it should not be defined in a constructor. `static final` variables should be set immediately upon declaration at the class level, while non-final `static` variables should be set by a static block. – Zircon Jul 19 '16 at 19:31
  • Sorry for the confusion and thank you for clarifying - `final` is the keyword I want to use in this instance. Should I set the value of variables that are keyworded `final` through declaration in the class code block? Also, how should I keyword these - `public`, `protected`, or `private`? I'm aware that I should encapsulate and use private by default, but I want to ensure the subclass also has the same value for the variable. – drs Jul 19 '16 at 19:37
  • Declaring `foodDogEats` to be `final` means that once you set it, it cannot be changed`. Should this be the functionality you want, you would set `foodDogEats` in the constructor, and use a getter but not a setter. If the food eaten does not change across instances of the class, you would make it `public static final`. This would be instantiated in a static code block. You can still use a getter for it, but it would most likely be accessed via `Fido.FOOD_DOG_EATS` instead. I recommend you research inheritance and static vs non-static variables to get better clarity on this subject. – Zircon Jul 19 '16 at 19:44
1

If a constructor does not explicitly invoke a superclass constructor, then the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.

Kintu Barot
  • 320
  • 2
  • 11