Java继承:在构造函数和继承方法中减少可见性。

6
在以下代码中,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!"); 
    }

    }  

1
这个链接解释了为什么重写方法不能有更严格的访问权限(请跳转到文本中间)。该答案讨论了以多态方式调用的方法。构造函数不是以多态方式调用的,因此相同的原因不适用。 - ajb
2个回答

14

构造函数不会被继承,所以 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 - brain storm
4
好的,那是另一个问题。每个构造函数都会调用超类构造函数(除了Object本身),无论是否有显式调用。如果没有显式调用,则Java会在子类构造函数中作为第一条语句插入对无参超类构造函数的隐式调用。如果超类构造函数是私有的,则当然无法访问。 - rgettman
1
所以构造函数不会被继承,但是总会调用超类的构造函数(无论是隐式还是显式地)来正确初始化字段,对吗? - brain storm
1
@brainstorm "只是为了初始化字段" ... 这通常是目的,用于初始化属于超类的字段。然而,如果您在超类中编写一个无参数构造函数,您可以将任何想要的内容放入其中 - 初始化一些字段,显示一些输出,向另一台计算机发送消息,擦除硬盘 - 如果它不是“private”并且您没有显式的super(...)构造函数调用,则子类构造函数会隐式调用它。 - ajb
@ajb:有道理。感谢澄清。 - brain storm

1
当扩展一个类时,您声明您的类是父类的扩展(“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中声明的方法,即printMessage和createAnA。
这就是为什么你可以使构造函数私有而不改变类的定义。那么,为什么在重写父类签名时不能将方法设为私有呢?这涉及到[class].method()的不同定义。假设您可以将方法设为私有。假设您在B类中声明了一个printMssage方法。您的理由是您只想在该方法内部使用该方法,并且在外部调用时要使用其父级的printMessage方法。现在,您在B类中编写了以下方法。
public void adjustMessage(String additional) {
    message = getMessage() + additional();
}

哪个版本的get message会被执行?你的私有版本还是父类的公共版本?Java调度程序当然会选择公共版本,因为它是在接口中声明的。因此,如果您确实使您的方法具有较低的特权,则永远无法调度您的方法,这将使读者感到困惑。

这是一个非常好的问题。


谢谢回复。你不能在超类中有私有构造函数。你的代码存在编译错误。 - brain storm
你可以在超类中拥有私有构造函数。 然而,如果你要扩展那个类,你必须有某种访问权限来构建它。 我已经更正了示例代码以证明这一点。 - Chuck Lowery

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接