【问题标题】:Java inheritance: Reducing visibility in a constructor vs inherited methodJava 继承:降低构造函数与继承方法的可见性
【发布时间】:2014-04-14 00:26:48
【问题描述】:

在以下代码中,Child 的构造函数将可见性从public 降低到private,这是允许的。继承的方法,例如test(),不能降低可见性。为什么 Java 会这样操作?

class Parent { 
        public Parent(){}

       public void test()  
        {  
            System.out.print("parent test executed!");  
        }
}

class Child extends Parent{  

    private Child(){}

    private void test(){
        System.out.print("child test executed!"); 
    }

    }  

【问题讨论】:

  • 这个link 解释了为什么覆盖方法不能有更严格的访问(转到文本的中间)。答案讨论了以多态方式调用的方法。构造函数不是多态调用的,所以同样的原因不适用。

标签: java inheritance methods constructor access-modifiers


【解决方案1】:

构造函数不会被继承,因此Child() 不会覆盖Parent()

至于方法,如果你有(如果Child()public

Parent p = new Child();
p.test();

如果允许,这将调用private 方法。因此,不允许在覆盖时缩小访问范围。

【讨论】:

  • 如果没有继承构造函数,使Parent构造函数Private,子类构造函数出现如下错误:Implicit super constructor Parent() is not visible. Must explicitly invoke another constructor
  • 嗯,这是另一个问题。每个构造函数都会调用一个超类构造函数(Object 本身除外),无论是否有显式调用。如果没有显式调用,则 Java 插入对无参数超类构造函数的隐式调用,作为子类构造函数中的第一条语句。如果超类的构造函数是private,那么当然是不可访问的。
  • 所以构造函数不会被继承,但总是调用超类构造函数(隐式或显式)只是为了正确初始化字段?
  • @brainstorm “只是为了初始化字段”......这是通常的目的,初始化属于超类的字段。但是,如果你在超类中编写一个无参数构造函数,你可以在其中放入任何你想要的东西——初始化一些字段,显示一些输出,向另一台计算机发送消息,擦除硬盘——它会被调用如果不是 private 并且您没有显式的 super(...) 构造函数调用,则由子类构造函数隐式调用。
  • @ajb:有道理。感谢您的澄清
【解决方案2】:

当扩展一个类时,您声明您的类是父类的扩展(“IS-A”关系)。这意味着您的类将拥有父类的所有方法。这与在 java 中实现接口相同,只是您从父级获得方法定义(和字段),而不仅仅是在接口中声明的方法。在接口中,构造函数不存在,因为它们不是方法。构造函数是特殊的,因为它们完全属于声明它们的类。他们声明如何只构建自己。

为了构造一个对象,你必须知道对象类。

    class A {
        private message;
        private A() {
            message = "You created an A";
        }

        public A(String message) {
            this.message = message; 
        }

        public void printMessage() {
            System.out.println(message);
        }

        public static A createAnA() {
            return new A();
        }
    }

    class B extends A {
        public B() {
            super("You created a B");
        }
    }

A anA = new B();  // This will work
A anotherA = new A(); // This is not allowed as the constructor is private
A yetAnotherA = A.createAnA(); // This works too

所以当我们构造 B 时,我们可以说它是一个 A。即使构造函数 A 是私有的,这是因为构造函数不是接口的一部分。当我们将 B 分配给类型 A 的字段时,我们对 B 的唯一说明是它具有在 A 中声明的方法。在本例中为 printMessagecreateAnA

这就是为什么您可以在不更改类定义的情况下将构造函数设为私有的原因。现在,为什么在覆盖父母签名时不允许将该方法设为私有。这涉及到[class].method() 的不同定义。假设您可以将您的方法设为私有。假设您在 B 类中声明了一个 printMssage。您的理由是您希望该方法仅在方法内部使用,并且您希望在外部调用时使用您的父母 printMessage 。现在,你在 B 类中写了一个这样的方法。

public void adjustMessage(String additional) {
    message = getMessage() + additional();
}

将执行哪个版本的获取消息?你的私人的还是你父母的公共的? Java 调度程序当然会选择公共的,因为它是在接口中声明的。所以我们看一下这个例子,我们可以看看你是否确实让你的方法具有不同的较低权限,你的方法也永远不会被调度,这只会让读者感到困惑。

这是一个很好的问题。

【讨论】:

  • 感谢您的回复。你不能在超类中有私有构造函数。您的代码本身存在编译错误
  • 你的超类中可以有私有构造函数。但是,如果您扩展该类,则必须具有某种访问权限才能构造它。我已经更正了示例代码以证明这一点。
猜你喜欢
  • 2018-11-20
  • 1970-01-01
  • 2014-12-27
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 2013-03-21
  • 2011-09-09
  • 2010-12-11
相关资源
最近更新 更多