40

这是工作的java代码

class Cup {
    public String sayColor() {
        return "i have a color .";
    }
}

class TCup extends Cup{
    public String sayColor(){
        System.out.println(super.getClass().getName());
        return super.sayColor()+"color is tee green.";
    }
}

class MyTCup extends TCup {
    public String sayColor(){
        System.out.println(super.getClass().getName());
        return super.sayColor()+"but brushed to red now!";
    }
}
class Test {
    public static void main(String[] args) {
        Cup c = new MyTCup();
        System.out.print(c.sayColor());
    }
}

并运行测试类打印

MyTCup
MyTCup
i have a color .color is tee green.but brushed to red now!

问题1:在运行时,对象C的类型是MyTCup,但它总是可以调用super方法。初始化对象后MyTCup内存中是否有方法堆栈,然后可以像代码一样在运行时调用?

问题2:没有办法在其他对象中调用super方法。据我所知,c++ 可以随时转换为调用父方法。为什么它在 Java 中有所不同?

4

4 回答 4

79

您不能在其他对象中调用 super 方法 - 这会违反封装。重点是对象控制其覆盖的方法的作用。例如,您可能会覆盖集合的add方法以在某些情况下引发异常,因此它可以确保仅将“有效”项目添加到集合中。如果调用者可以通过演员绕过它,那将毫无意义!

对象自己调用的唯一原因super.foo()是通过使用父实现来实现一个调用。这取决于类中的代码,以确保它只明智地做到这一点。同样,以 add-in-a-collection 为例,如果集合覆盖add它必须有某种方法将验证的项目添加到集合中,它会使用super.add().

请注意,出于相同的封装原因,您只能调用父实现,而不是祖父实现 - 所以super.foo()是有效的,但super.super.foo()不是。

于 2009-06-23T14:28:20.227 回答
1

1:

你的问题不是很清楚。“像代码一样在运行时调用”是什么意思?如果您要问实例 c 如何知道它的超类是什么,那么是的,类层次结构存储在内存中,并且可以被 VM 访问。

2:

Java 实际上确实允许您将实例强制转换为其父级。只是在实例上调用方法总是使用实例的实际类,而不是它的编译时类。即在Java 中,所有方法都是C++ 中所谓的“虚拟”方法。为什么这样决定我不知道。

编辑:实际上 Jon Skeet 很好地解释了为什么你不能在子类的实例上调用超类的方法,所以现在我知道了:-)。

于 2009-06-23T14:31:58.893 回答
1

您可以在子类中定义一个新的辅助方法,这样您就不会覆盖原来的——调用它——它可以调用或不调用超级方法,这取决于你想要什么。

于 2011-07-18T18:24:00.717 回答
0

实际上你可以,但你必须使用一种方法,所以它只适用于你的代码。
在超类中,将参数“Class”添加到方法中,如:

public String sayColor(Class classFilter){...

现在,在每次覆盖时,您检查当前子类是否是指定过滤器之一,例如:

if(TCup.class!=classFilter)return super.sayColor(classFilter);
return "some text for TCup only";

我以独特的方式编码。您可以添加更多参数,或者与 null 进行比较,这样您就可以将结果与超类连接起来,发挥您的创造力 :)

于 2016-09-25T22:14:50.653 回答