我从berkley cs数据结构网络广播得到了这个:
class A {
void f() {System.out.println("A.f");}
void g() {f();}
// static void g(A y) {y.f();}
}
class B extends A {
void f(){
System.out.println("B.f");
}
}
class C {
static void main (String[] args){
B aB = new B();
h (aB);
}
static void h (A x) {x.g();}
//static void h (A x) {A.g(x);} what if this were h
}
你能告诉我打印出来的原因和原因吗?教练说B.f,但我不明白为什么。我以为是A.f.谢谢(不,我不在课堂上,只是想学习。)
编辑:对于我从视频讲座中复制的错误感到抱歉。
答案 0 :(得分:2)
此示例演示了面向对象编程的强大功能。
因为ab是B的实例,所以对ab的任何方法调用都将使用B,中定义的函数,即使这些函数是通过超类中定义的函数间接调用的。
这个例子是如此抽象,以至于其优点可能并不清楚。让我做一个更现实的例子:
class Employee
{
... bunch of stuff ...
void calcPay()
{
pay=hoursWorked*hourlyRate;
}
void produceCheck))
{
calcPay();
calcTaxes();
calcBenefitDeductions();
printCheck();
}
}
class Salesman extends Employee
{
void calcPay()
{
pay=sales*commissionRate;
}
}
... somewhere else ...
for (Employee employee1 : employeeList)
{
employee1.produceCheck();
}
我遗漏了各种各样的细节来说明问题:这段代码不会编译。
但是重点在于:推销员有一种不同的方法来计算他们的工资,而不是其他员工:他们是按佣金而不是每小时支付的。 (在现实生活中,我们大概也有受薪员工,但正如我所说,我正在简化。)计算任何类型员工薪酬的功能都是从一个更大的功能中调用,也可以做其他事情。面向对象编程的优点在于我们可以调用外部函数,而不关心我们调用它的对象是普通的Employee还是Salesman。每个对象都知道它是什么,并调用正确的函数。在示例的最后几行中,我们有一些包含常规Employees和Salesmen的结构,我们可以遍历并处理它们而无需检查它们的类型。没有OOP,我们必须不断编写如下代码:“if(type == SALESMAN)... else if(type == HOURLY)...”
答案 1 :(得分:1)
“B.f”打印的原因是因为方法的实现是由对象的运行时类型决定的,而不是它的编译时类型。它就像C ++中的virtual
关键字。
构建B
后,即使f
被称为B
,您也知道调用其A
方法会打印“Bf”。
此外,您的A.f
方法缺少近距离支撑。
答案 2 :(得分:1)
该代码不正确,A.g()不接受任何参数。
static void h (A x) {A.g(x);}
A.G(X);试图在A上调用一个静态方法,用x作为参数。 对于您发布的代码示例,这是不可能的。
除了错误的代码之外,原因是B用自己的实现覆盖方法f()。 因此B的任何实例,例如B x = new B();将调用B定义的不是A.f()的f()。到达A.f()的唯一方法是通过调用super.f()来自B的实例内部。