Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么派生类重写方法不应该比java中的基类更严格?_Java - Fatal编程技术网

为什么派生类重写方法不应该比java中的基类更严格?

为什么派生类重写方法不应该比java中的基类更严格?,java,Java,为什么派生类重写方法不应该比java中的基类更具限制性。为什么编译器会抛出错误?您能解释一下原因吗?关键是,只知道您的超类的调用方应该仍然能够使用给定的子类的任何实例。考虑这种情况: public class Super { public void print() { System.out.println("Hello!"); } } public class Sub extends Super { @Override void prin

为什么派生类重写方法不应该比java中的基类更具限制性。为什么编译器会抛出错误?您能解释一下原因吗?

关键是,只知道您的超类的调用方应该仍然能够使用给定的子类的任何实例。考虑这种情况:

public class Super
{
    public void print()
    {
        System.out.println("Hello!");
    }
}

public class Sub extends Super
{
    @Override
    void print() // Invalid
    {
        System.out.println("Package access");
    }
}
现在,从另一个包中,想象我们有:

public void printSuper(Super x)
{
    x.print();
}
我们称之为:

printSuper(new Sub());
你希望它能做什么?您正在重写该方法,因此它应该打印“包访问”-但这意味着您正在从不同的包调用包访问方法


基本上,这只是一个实际的例子。您应该能够将子类的任何实例视为超类的实例,很难看出这与使子类中的内容更具限制性相适应。

您不能使访问修饰符更具限制性,因为这违反了继承的基本规则,即子类实例应可替换为超类实例。

例如 假设Person类有getName公共方法,许多类(包括非子类)都在使用该方法,但有人只是将Employee添加为Person和getName的子类 Employee受保护,只能由子类访问,然后以前的代码将开始中断,Employee将不会被替换到Person对象

因此,java决定实施此限制。

考虑下面的示例

class Mammal {
    public Mammal readAndGet() throws IOException {//read file and return Mammal`s object}
}

class Human extends Mammal {
    @Override
    public Human readAndGet() throws FileNotFoundException {//read file and return Human object}
}
如果我们执行下面的代码

Mammal mammal = new Human();
Mammal obj = mammal.readAndGet();
我们知道,对于编译器,从类
哺乳动物
的对象调用.readAndGet()
,但是在运行时,JVM将解析
哺乳动物.readAndGet()
方法调用类
人类
的调用,因为
哺乳动物
持有
新人类()

方法
readAndGet
哺乳动物
中定义为public,为了减少类
人类
中的限制,我们需要删除访问说明符(使其成为
默认值
),或使其
受保护
私有

现在假设

  • 如果我们在
    Human
    中将
    readAndGet
    定义为
    default
    protected
    ,但
    Human
    在另一个包中定义
  • 如果我们将
    readAndGet
    定义为人类的私有
我们知道JVM将在运行时解析
readAndGet
方法调用,但编译器不知道这一点,并且在这两种情况下,代码都将成功编译,因为for compiler
readAndGet
是从类
哺乳动物
调用的

但在这两种情况下,JVM在运行时都无法从Human访问
readAndGet
,因为在
Human
类中对
readAndGet
的访问受到限制

而且我们也不能确定将来谁将扩展我们的类,他将在什么包中进行扩展,如果那个家伙使覆盖方法的限制性更小,JVM可能无法调用该方法,代码将在运行时中断

因此,为了避免这种不确定性,根本不允许为子类中的重写方法分配限制性访问权限


重写方法时,我们还需要遵循其他规则,您可以阅读更多内容以了解原因。

重写消息不应比重写方法更具限制性,因为子类的实例应始终能够在超类的实例所在的位置使用预期。但是,如果一个方法限制性更强,那么如果调用来自另一个类或包,则可能无法访问该方法。例如,想象一下:

//File Number 1
public class Human {
    public int age = 21;
    public int getAge() {
        System.out.println("getAge() method in Human");
        return age;
    }
}

//File Number 2
public class Teacher extends Human {
    public int getAge() {
        System.out.println("getAge() method in Teacher");
        return age;
    }
}

//File Number 3
public class Characteristics {  
    public static void showAgeOfObject(Human human) {
        human.getAge();
    }

    public static void main(String[] args) {
        Human human = new Human();
        Teacher teacher = new Teacher();

        showAgeOfObject(human);     
        showAgeOfObject(teacher);
    }
}
现在,如果这两个getAge()方法都是公共的,那么将显示它

getAge() method in Human
getAge() method in Teacher

但如果Teacher中的getAge()是private,这将抛出一个错误,因为我们在另一个类中,因此无法访问该方法

您可以引用Liskov替换原则,如果您不希望用户能够在您自己的实现中使用该函数,您可以始终使用空版本覆盖它。这样类的接口就不会中断。当然,你必须根据对给定函数的期望来决定这种方法是否有意义。@JonSkeet我很懒,不想写一个新的答案来说明这一点,所以我只是添加了一个提醒-知道你的声誉,我不应该怀疑你会添加它:-)