java 从child调用类属性与调用super有什么显著的区别吗?

k5hmc34c  于 2023-08-02  发布在  Java
关注(0)|答案(3)|浏览(86)

我是Java新手,所以请原谅我的无知。
从父类隐式地为类属性设置值与使用构造函数和调用super之间有什么有意义的区别吗?
我认为我没有正确地解释我的意思,所以这里有一个具体的例子

public class Parent {
    protected String name;
}

public class Child extends Parent{
    public Child() {
        this.name = "Child";
    }
}

字符串
相对于

public class Parent {
    protected String name;

    public Parent(String name) {
        this.name = name;
    }
}

public class Child extends Parent{
    public Child() {
        super("Child");
    }
}


这段代码本质上做了同样的事情。如果setter/getter存在于父类或子类中,它们的工作方式与您期望的工作方式差不多。

58wvjzkj

58wvjzkj1#

在您的两个示例中,通过new Child();创建Child对象将导致子对象的String name字段设置为"Child"
构造函数链接通常是为了使代码更易于维护并避免重复代码。例如,我们假设String name属性不是使用固定值,而是必须传递到构造函数中的参数。我们还想禁止String name属性的null值,并在用户试图通过将null传递到构造函数中来创建Object时抛出错误。
如果没有构造函数链和调用super(name),你最终会得到这样的代码:

public class Parent {
    protected String name;

    public Parent(String name) {
        if(name == null) {
            throw new IllegalArgumentException("Name cannot be null!");
        }
        this.name = name;
    }
}

public class Child extends Parent{
    public Child(String name) {
        if(name == null) {
            throw new IllegalArgumentException("Name cannot be null!");
        }
        this.name = name;
    }
}

字符串
而如果你使用构造函数链接,你就不必写重复的代码,因为你可以把所有的逻辑都放在总是被调用的父构造函数中:

public class Parent {
    protected String name;

    public Parent(String name) {
        if(name == null) {
            throw new IllegalArgumentException("Name cannot be null!");
        }
        this.name = name;
    }
}

public class Child extends Parent{
    public Child(String name) {
        super(name);
    }
}

ctrmrzij

ctrmrzij2#

正如你正确提到的,这段代码做同样的事情。然而,在这种特定情况下,使用public Parent(String name)有一些相互关联的优点:

  • 它使您能够将字段String name标记为final,在这种情况下实际上意味着什么。
  • 更简单的是:你可能期望Parent类定义了name,所以它不应该依赖于Child类是如何实现的,或者它是否存在。
  • 它将实现基本的OOP原则:封装
inn6fuwd

inn6fuwd3#

这个问题很抽象,所以我的答案也很抽象:)
正如您所指出的,对于这个特定的实现,这并不重要,从技术上讲,您正在做同样的事情。但是,您可能对如何分配字段有一些逻辑(尽管,我个人反对构造函数中的任何逻辑,除了字段分配)。例如,你可能想“清理”你的name,通过替换尾随的空格等等。或者检查名称是否有效或不为空,那么将它放在父类中将是有益的,这样任何子类都不会混淆逻辑。这意味着您的第二个示例更适合这种情况。它可能是相反的,当你需要在孩子身上做一些特殊的清理,而不是在父母身上,那么第一个例子更好。这是从实际的Angular 。
我个人认为第二个例子更好,因为它通常使代码更简单。我通常甚至试图避免setter,并使字段final,甚至可能是私有的。换句话说,如果这个name字段属于Parent,那么让parent分配它,不要试图干预。然后,每次当你看到name是错误的,或者你需要以某种方式改变你如何分配名称的逻辑,你知道一个唯一的地方这样做。也许明天你会决定引入两个额外的字段firstNamelastName,逻辑将是这样的:用空格分隔姓名并指定名字和姓氏。如果使用第一个示例,则需要重复此逻辑。在第二个示例中,您只需要挂钩到Parent的构造函数。

相关问题