我在这里使用超类构造函数调用是否必要?

时间:2016-07-19 18:34:24

标签: java oop inheritance constructor

我是Java的新手,并且仍然通过面向对象的设计和编程实践基础知识。我有一些关于继承,对象创建和super()调用的正确用法的问题。

请考虑以下事项:

超类,

package pet

public class Dog {

    private String foodDogEats;

    public Dog() {
        this.foodDogEats;
    }

    public String getDogFood() {
        return foodDogEats;
    }

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

}

子类中,

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());
    }

}

和控制器。

package pet

public class MyDogFido {

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

}

此示例中的对象是,实例化一个新的Fido对象,并在此过程中执行whatDoesFidoEat()中的打印行为。我有几个问题 -

由于我已经调用了一个新的Fido对象(它是Dog的扩展,如果我没记错地继承了它的方法和变量),那么实例化一个新的Dog Fido()构造函数中的对象是多余的?

使用super()怎么样?

哪种行为正确 - 在Dog中实例化Fido()对象,调用super(),或两者兼而有之?

我最初在控制类中使用两者编写了一些类似的代码。但是,在写完这个问题后,我的直觉告诉我,我应该只拨打super()

您可以随意评论我的示例代码(尤其是this.foodDogEats;构造函数中的Dog()行 - 也不确定其中的用法)。

谢谢!

5 个答案:

答案 0 :(得分:7)

Dog dog = new Dog();行是多余的,你是对的。它将创建第二个完全独立的Dog对象。

super()来电也是不必要的。除非通过调用不同的超级构造函数来覆盖该行为,否则所有Java构造函数都会隐式调用super()

答案 1 :(得分:2)

  

由于我已经调用了一个新的Fido对象(它是Dog的扩展,如果我没记错地继承了它的方法和变量),那么实例化一个新的Dog Fido()构造函数中的对象是多余的?

它不是多余的本身,但它是毫无意义和浪费的。您正在实例化一个新的不同的 Dog,然后忽略它。垃圾收集器最终会将其清理干净,但您从一开始就不需要它。您可以在类构造函数和方法中引用的Fido this a Dog。你不需要在构造函数中做任何事情就可以做到这一点,并且你不能在构造函数中做任何事情来阻止它这样做。

  

如何使用super()

如果类的构造函数没有显式调用同一个类的另一个构造函数或者一个超类的构造函数,那么它会隐式调用super()。在这种情况下,如果超类没有这样的无效构造函数,那么这是一个错误。显式调用super()并不完全是多余的,因为这会抑制隐式调用,但没有必要这样做。

  

哪种行为正确 - 在Dog中实例化Fido()对象,调用super(),或两者兼而有之?

通过直接或间接调用其构造函数之一来初始化超类。如果超类具有一个无效的构造函数,那么该调用可以是隐式的,如果那是你想要调用的那个。

  

您可以随意评论我的示例代码(尤其是this.foodDogEats;构造函数中的Dog()行 - 也不确定其中的用法)。

您引用的行是错误的。如果允许,我希望它评估为默认值this.foodDogEatsnull),没有其他影响。那将是毫无意义的。

此外,您的setDogFood()方法很奇怪。属性设置器通常具有以下形式:

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

您的原始版本有点无意义。

答案 2 :(得分:1)

您的代码应该在超类中显示编译器错误。

让我们了解你的逻辑:

在超级课程中

this.foodDogEats; // should be a compiler error

您认为它有什么作用?它什么都不做,因为它只是一个声明。这个'这个'关键字仅表示您指的是您创建的对象的特定实例中的变量,但您不会对其执行任何导致错误的操作。

在你的子类中,你不需要调用super,因为默认情况下会自动调用super,除非你在超类中没有无参数构造函数。

答案 3 :(得分:1)

您对super()的使用是正确的。 您完全没有使用Dog对象。

通过展开DogFido会继承Dog的非私有字段和方法。因此,您可以简化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);
    }

}

然后,简化您对它的使用:

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();
    }

}

您仍然可以使用Fido()构造函数调用whatDoesFidoEat,但由于对象的创建似乎并不依赖于该方法,因此我发现更好的做法是避免在构造函数中进行类似的调用。

修改

如果您想在构建时定义foodDogEats,可以定义构造函数Fido(String)

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

或者如果您的foodDogEats依赖于而不是实例,并且永远不会更改,则可以创建变量public static final FOOD_DOG_EATS。注意 - 通过Fido.FOOD_DOG_EATS访问它将与Dog.FOOD_DOG_EATS不同,因为静态变量不会被继承。

答案 4 :(得分:1)

如果构造函数没有显式调用超类构造函数,那么Java编译器会自动插入对超类的无参数构造函数的调用。如果超类没有无参数构造函数,则会出现编译时错误。对象确实有这样的构造函数,因此如果Object是唯一的超类,则没有问题。