写出以下代码的输出结果class A{
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
}
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class C extends B{}
class D extends B{}class test{
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.f(b)); A and A
System.out.println(a1.f(c)); A and A
System.out.println(a1.f(d)); A and D
System.out.println(a2.f(b)); B and A
System.out.println(a2.f(c)); B and A
System.out.println(a2.f(d)); A and D
System.out.println(b.f(b)); B and B
System.out.println(b.f(c)); B and B
System.out.println(b.f(d)); A and D
}
旁边的是标准答案,前三个都很好理解,但是后面三个真的是一头雾水啊,难道b,c都变成类A了?还有d,是不是如果子类里没有他的方法可调用,就看超类里是否有与他相对应的方法?
然后最后一个,b不是已经声明为B类了吗?为什么会调用A类里的方法呢?为什么结果不能是B and B呢?大家能帮忙给小弟解解惑吗?真是一头雾水啊!~~~~~~~~~~~
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
}
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class C extends B{}
class D extends B{}class test{
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.f(b)); A and A
System.out.println(a1.f(c)); A and A
System.out.println(a1.f(d)); A and D
System.out.println(a2.f(b)); B and A
System.out.println(a2.f(c)); B and A
System.out.println(a2.f(d)); A and D
System.out.println(b.f(b)); B and B
System.out.println(b.f(c)); B and B
System.out.println(b.f(d)); A and D
}
旁边的是标准答案,前三个都很好理解,但是后面三个真的是一头雾水啊,难道b,c都变成类A了?还有d,是不是如果子类里没有他的方法可调用,就看超类里是否有与他相对应的方法?
然后最后一个,b不是已经声明为B类了吗?为什么会调用A类里的方法呢?为什么结果不能是B and B呢?大家能帮忙给小弟解解惑吗?真是一头雾水啊!~~~~~~~~~~~
解决方案 »
- setLocationRelativeTo(null)不起作用怎么回事
- 为什么怎显示
- java 热键OR快捷键OR总之各种键
- NullPointerException抛错!
- 关于流的一个问题
- 软件设计师水平考试与资格考试的区别是什么呢?
- JAVA的概念题,高手来看看~~
- javac的时候只要我的源程序中有格式或注释,就都提示“illegal character”,怎么办?
- 大家来谈谈阅读thking in java 第15章(分布式计算)的感受,,
- 大神求助,tomact启动报错
- 我在官方网站下载了JDK1.5.0_09,在jdk目录中却没有发现docs子目录,而且src子目录打开是空的,不知为什么,求解!谢谢了
- 求助!~~ftp,http文件上传,下载
父类(可以是类,也可以是接口)的对象可以通过实例化子类来产生,最容易理解的是父类为接口时,当要得到父类的对象时可以new 子类来产生
例如:List list = new ArrayList();
这里 A a2 = new B();
B b = new B();
,但是 后面的输出为
System.out.println(a2.f(b));-》B and A , 我觉得应该是 B and B才对呀
而这里 System.out.println(a2.f(d)); A and D , a2又调用了超类里的方法 ,我觉得应该是 B and B才对
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
}这个类编译能通过吗?
方法前面是一模一样!!!!
super.f(o)
this.f((super)o)
super.f((super)o);
按照这个在看看
System.out.println(a1.f(b)); A and A
System.out.println(a1.f(c)); A and A
和
System.out.println(b.f(b)); B and B
System.out.println(b.f(c)); B and B解释大家都没有异议吧 简单的方法调用 第一、二行 是new A()实例调用的是A.f(A obj)第三、四行 是new B()实例调用的是B.f(A obj)关于
System.out.println(a2.f(b)); B and A
System.out.println(a2.f(c)); B and A解释一般人会认为a2的实际型别是Ba2.f()根据java的动态方法调用机制,实际上调用的是B.f()而B.f有2个重载 就有点迷糊了。实际上 这是不是重载问题而是一个简单的覆盖问题 A.f(A obj)被 B.f(A obj)覆盖了a2.f(A obj)实际执行的就是是B.f(A obj)至于
System.out.println(a2.f(d)); A and D
因为A有准确的D型别方法f(D obj) 所以就调用A.f(D obj)
public String f(B obj){return ("B and B"); ???
piaopiao11()
jin_marshal(Sunnywolf)挺有道理的
1)、a2是作为A来看待的
2)、由于原因1),所以a2不能调用A中不存在的方法
3)、B中的方法public String f(B obj){return ("B and B");}不存在于A类中,所以a2不会调用这个方法,不会输出"B and B"
4)、但是B覆盖了A的方法为public String f(A obj){return ("B and A");}
5)、a2本身其实是B类的实例,又4)中B的方法存在于A中,所以调用了public String f(A obj){return ("B and A");}
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
}
class B extends A{
public String f(B obj){return ("B and B");}--不是多态,定义了一个新的成员函数
public String f(A obj){return ("B and A");}
}
public String f(A obj){return ("B and A");
override这帖子不看了 再看就要气暴了
就是一个简单的覆盖方法 还有这么多异议
System.out.println(a2.f(b)); B and A先进行方法的重载:
a2 是被声明为A的,所以a2.f()找的是A类中的方法A.f()
b是被声明为B的,B extends A,所以a2.f(b)先被确定为A.f(A)
然后才是动态绑定:
a2=new B(),a2的实际类型是B,所以绑定为B.f(A)
System.out.println(a2.f(b)); B and A
中的b是B的一个对象,a2也是B的一个对象,
而且B中也有public String f(B obj){return ("B and B");}
为什么不调用上面的,而要调用下面的这个:
public String f(A obj){return ("B and A");}不解,不知道各们是不是可以解释一下
所以重载的时候把它看做A
而动态绑定的时候才把它看做B
因为a2是被声明为A的啊
所以重载的时候把它看做A
而动态绑定的时候才把它看做B你这解释也是有道理的,但是我按照上面那个仁兄的优先方法来想问题就有点说不过去了,其优先方法如下:方法调用的优先问题this.f(o)
super.f(o)
this.f((super)o)
super.f((super)o);
按照这个在看看
{ System.out.println(a.f(b));
}然后调用的时候:f2(new B(),newB());
this.f(o)
super.f(o)
this.f((super)o)
super.f((super)o);
是在进行方法重载的时候的顺序,它并没有涉及方法的覆盖(动态绑定)顺序
重载过程:
this.f(o)------A.f(B),不存在的方法
super.f(o)--------A无父类,不进行
this.f((super)o)---------A.f(A) 找到,所以重载的结果是A.f(A)
super.f((super)o);
输出本来就是 B and B
a1为A的对象,a2是B的对象
请看下面的程序:
public class A{
public String f(D obj){return ("A and D");}
public String f(B obj){return ("A and B");}
public String f(A obj){return ("A and A");}
public String display(){return ("A的对象" );}
}
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
public String display(){return ("B的对象" );}
}
class C extends B{}
class D extends B{}class test{
public static void main(String args[]){
A a1 = new A();
A a2 = new B();//a2为B的对象
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.display());
System.out.println(a2.display());
System.out.println(b.display());
System.out.println(c.display());
System.out.println("a1.f(a2) "+a1.f(a2));
System.out.println("a1.f(b) "+a1.f(b));
System.out.println("a1.f(c) "+a1.f(c));
System.out.println("a1.f(d) "+a1.f(d));
System.out.println("a2.f(a1) "+a2.f(a1));
System.out.println("a2.f(b) "+a2.f(b));
System.out.println("a2.f(c) "+a2.f(c));
System.out.println("a2.f(d) "+a2.f(d));
System.out.println("b.f(a2) "+b.f(a2));
System.out.println("b.f(b) "+b.f(b));
System.out.println("b.f(c) "+b.f(c));
System.out.println("b.f(d) "+b.f(d));
}
}
/////////////////////////////////////////////////////////
/////////////////////////////////
////////////////
//////
输出位:
A的对象
B的对象
B的对象
B的对象
a1.f(a2) A and A
a1.f(b) A and B
a1.f(c) A and B
a1.f(d) A and D
a2.f(a1) B and A
a2.f(b) B and B
a2.f(c) B and B
a2.f(d) A and D
b.f(a2) B and A
b.f(b) B and B
b.f(c) B and B
b.f(d) A and D
其实这是多态的问题了~在多态中方法是后期才绑定的~~也就是只有在运行才能确定调用的方面
我给你讲讲多态的调用规则吧,希望你能明白你的例子的输出缘由!!在多态中的调用有这样的规则:
调用成员变量时,将调用引用类型所对应的类中的成员变量的,如果该类中没有定义的该变量,才会调用父类(有定义)的同名成员变量。调用成员方法时,将根据对象的运行时的类型来确定调用哪个成员方法,也就是说运行时类型是哪个类的引用,就调用哪个类中定义的成员方法楼上的说调用成员方法,那System.out.println("a1.f(a2) "+a1.f(a2));中的a1.f(a2)应该算是运行类A的引用a1那调用方法也自然是调用A的成员方法,那么调用的方法应该是根据参数来确定吧,参数是a2(类B),那么应该是调用 public String f(B obj){return ("A and B");}才对.这是我的理解,请大家指点一下,实在迷惑
"谁能给我解释一下下面这一句是为什么?谢谢! System.out.println(a2.f(b)); B and A"
输出本来就是 B and B
a1为A的对象,a2是B的对象
请看下面的程序:
public class A{
public String f(D obj){return ("A and D");}
public String f(B obj){return ("A and B");}
public String f(A obj){return ("A and A");}
public String display(){return ("A的对象" );}
}
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
public String display(){return ("B的对象" );}
}
class C extends B{}
class D extends B{}class test{
public static void main(String args[]){
A a1 = new A();
A a2 = new B();//a2为B的对象
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.display());
System.out.println(a2.display());
System.out.println(b.display());
System.out.println(c.display());
System.out.println("a1.f(a2) "+a1.f(a2));
System.out.println("a1.f(b) "+a1.f(b));
System.out.println("a1.f(c) "+a1.f(c));
System.out.println("a1.f(d) "+a1.f(d));
System.out.println("a2.f(a1) "+a2.f(a1));
System.out.println("a2.f(b) "+a2.f(b));
System.out.println("a2.f(c) "+a2.f(c));
System.out.println("a2.f(d) "+a2.f(d));
System.out.println("b.f(a2) "+b.f(a2));
System.out.println("b.f(b) "+b.f(b));
System.out.println("b.f(c) "+b.f(c));
System.out.println("b.f(d) "+b.f(d));
}
}
/////////////////////////////////////////////////////////
/////////////////////////////////
////////////////
//////
输出位:
A的对象
B的对象
B的对象
B的对象
a1.f(a2) A and A
a1.f(b) A and B
a1.f(c) A and B
a1.f(d) A and D
a2.f(a1) B and A
a2.f(b) B and B
a2.f(c) B and B
a2.f(d) A and D
b.f(a2) B and A
b.f(b) B and B
b.f(c) B and B
b.f(d) A and D
------------------------------------------
因为a2是被声明为A的啊
所以重载的时候把它看做A
而动态绑定的时候才把它看做B
所以调用a1.f(a2)时候把a2看成A的对象,自然调用A类中的public String f(A obj){return ("A and A");}方法
类似b.f(a2) B and A也可以解释通!
super.f(o)
this.f((super)o)
super.f((super)o);
按照这个在看看
super();对象可以使用父类的所有方法和变量。
this();可以访问父类和子类中所有的方法或变量(父类中的构造方法除外)。这个回答就是最正确的了~你慢慢体会体会
涉及到了"运行时类型识别".
默认状态(和强制类型转换状态相区别)下,对象只能调用父类方法和父类变量。此种情况下,还有两种不同的情况:
▲被调用方法是被该子类覆盖的方法,这时其实是显式调用父类方法,实际上是调用该子类方法和该子类变量,这时父类变量不能被该方法修改,被修改的是该子类变量。(也就是后期绑定.)
▲被调用方法没有被该子类覆盖,这时是调用父类方法,父类变量可以被该方法修改。
不建议还是在调用时准确表明匹配哪个类的方法。想楼主那样的程序在实际应用中我实在不敢苟同。
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
因为a2在静态联编时,a2是被认为是A类的,
a2在匹配函数是从超类开始的,后再到子类,看是否有重写的函数,以实现多态;
可以测试如下;
class B extends A{
public String f(B obj){return ("B and B");}
//public String f(A obj){return ("B and A");}//屏蔽这一行
}
System.out.println(a2.f(b));// 结果为A and A;
而b在静态联编时,就是个B类,
b在匹配函数就是从本类开始,
若未找到函数,就再上朔到超类,
这样就不难理解了,
System.out.println(b.f(d)); A and DC和D都tmd是从直接B继承来的,怎么结果会不一样?
System.out.println(b.f(c)); B and B
System.out.println(b.f(d)); A and DC和D都tmd是从直接B继承来的,怎么结果会不一样?因为,B是A的子类,而A类实现了f(D ),而C则不同了,A和B类都实现f(c),所以C必须向上转形.不知道是不是说明白了.我的理解是这样的.
大家犯迷糊的地方主要是a2.f(b)和a2.f(c)的输出。
经过我的测试,
A a2= new B();之后,a2的类型和属性问题我们要弄清楚,经过这个向上转型后,a2的类型是A类,a2里的属性方法有f(D obj)和f(A obj)这两个,f(A obj)是B类的那个方法,它覆盖了A类的f(A obj)。所以
a2的方法是:{ public String f(D obj){return ("A and D");
public String f(A obj){return ("B and A");}
}
所以,a2.f(b)和a2.f(c)的输出是:B and A,这里c向上转型到A类型。我已经说得够清楚了。
{ public String f(D obj){return ("A and D");
public String f(B obj){return ("B and B");
public String f(A obj){return ("B and A");
}
因此,a2.f(b)和a2.f(c)首先匹配f(B obj),导致输出结果是B and B.
A类没有B类的f(B obj)方法,当B向上转型时,对象a2会丢失B的f(B obj)方法。这里还涉及了方法覆盖问题,B类的f(A obj)方法覆盖了A类的f(A obj)。
我们来看看经过上面的类定义后,B类包含的方法:
1)public String f(D obj){return ("A and D");}
2)public String f(B obj){return ("B and B");}
3)public String f(A obj){return ("B and A");}所以在调用System.out.println(b.f(d));时,自然会找到最匹配的方法1),输出结果也就是:A and D了!
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
就是A类中的方法,所以在调用时只要传进来的对象不是D类的对象就一律返回"A and A"(因为A类是这里的根类),要不就返回"A and D"。
接下类的三个就比较有意思,a2是一个指向子类对象的引用,也就是说用它调用方法时只能调用
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
为什么他可以调用子类中的方法呢?原因就在于他其实没有调用子类中的方法,只是因为子类中的一个方法把它的一个方法给覆盖掉了(A类的第二个方法和B类的第二个方法同名且同参),所以,当父类引用调用public String f(A obj)时,实际执行的却是子类中的相同的方法,即相当于他能调用的方法变成了
public String f(D obj){return ("A and D");}
public String f(A obj){return ("B and A");}
所以在传进去的参数不是D类的对象时都会返回"B and A"。是D类的对象则返回“A and D”
最后的三个更容易理解,B类引用b指向的是B类对象,所以他就可以调用按理说是A类和B类的共计4个方法,但是因为用两个是同名又同参的所以就只有三个,即:
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
public String f(D obj){return ("A and D");}
所以会有最后三个的输出!!!
我又对这个问题做了一下总结,如下:这几个类到最后变成这样的了:
class A{
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
}
class B extends A{
public String f(D obj){return ("A and D");}
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class C extends B{
public String f(D obj){return ("A and D");}
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class D extends B{
public String f(D obj){return ("A and D");}
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class test{
public static void main(String[] ss)
{
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.f(b));
//A and A 调用含b的方法,没有找到,就找到含它的父类A的方法,
//即public String f(A obj){return ("A and A");}
----------------------------------------------
System.out.println(a1.f(c)); //A and A 同上
----------------------------------------------
System.out.println(a1.f(d)); // A and D 这个就不用说了吧
----------------------------------------------
System.out.println(a2.f(b));
/* B and A 这里,用父类的引用指向子类的对象,但父类的引用只能调用子类中和父类完全一致的方法,
也就是说,这里可以用的方法只有这两个:
public String f(D obj){return ("A and D");}
public String f(A obj){return ("B and A");}
也就是说出现了和第一个一样的情况了,要找它的父类的那个f(A obj);
----------------------------------------------
System.out.println(a2.f(c)); // B and A 同上了
System.out.println(a2.f(d)); // A and D
-----------------------------------------------
System.out.println(b.f(b)); // B and B
System.out.println(b.f(c)); // B and B这个因为它的直接父类的是f(B obj)
System.out.println(b.f(d)); // A and D
}
}
if (rootArgumentType == Object.class) {
return null;
}
LinkedList classQueue = new LinkedList();
classQueue.addFirst(rootArgumentType); while (!classQueue.isEmpty()) {
Class argumentType = (Class)classQueue.removeLast();
// Check for a visit method on the visitor class matching this
// argument type.
try {
if (logger.isDebugEnabled()) {
logger.debug("Looking for method " + VISIT_METHOD + "(" + argumentType + ")");
}
return findVisitMethod(this.visitorClass, argumentType);
}
catch (NoSuchMethodException e) {
// Queue up the argument super class if it's not of type Object.
if (!argumentType.isInterface() && (argumentType.getSuperclass() != Object.class)) {
classQueue.addFirst(argumentType.getSuperclass());
} // Queue up argument's implemented interfaces.
Class[] interfaces = argumentType.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
classQueue.addFirst(interfaces[i]);
}
}
}
// No specific method found -> return the default.
return findDefaultVisitMethod();
} private Method findVisitMethod(Class visitorClass, Class argumentType) throws NoSuchMethodException {
try {
return visitorClass.getDeclaredMethod(VISIT_METHOD, new Class[] {argumentType});
}
catch (NoSuchMethodException ex) {
// Try visitorClass superclasses.
if (visitorClass.getSuperclass() != Object.class) {
return findVisitMethod(visitorClass.getSuperclass(), argumentType);
}
else {
throw ex;
}
}
}spring中的代码,有助于大家理解。
using namespace std;class D;class A
{
public:
virtual string f(D* obj){return string("A and D");}
virtual string f(A* obj){return string("A and A");}
};
class B : public A
{
public:
virtual string f(B* obj){return string("B and B");}
virtual string f(A* obj){return string("B and A");}
};
class C : public B
{};
class D : public B
{};int main(int argc, char* argv[])
{
A* a1 = new A;
A* a2 = new B;
B* b = new B;
C* c = new C;
D* d = new D; cout << a1->f(b) << endl; //A and A
cout << a1->f(c) << endl; //A and A
cout << a1->f(d) << endl; //A and D
cout << a2->f(b) << endl; //B and A
cout << a2->f(c) << endl; //B and A
cout << a2->f(d) << endl; //A and D
cout << b->f(b) << endl; //B and B
cout << b->f(c) << endl; //B and B
cout << b->f(d) << endl; //B and B,此处与java的结果不同?
return 0;
}
在C++中,多态由指针或引用加上虚函数来实现,每个含有虚函数的类有一个或几个虚函数表,每个这样的类的对象有一个或几个指向虚函数表的指针,为什么说有一个或几个呢,主要是继承的原因吧。为什么会有上面的结果呢,主要因为对象(指针)的类型和首先调用哪个(继承来的父类的虚函数表,其中有些已被改写,还是自己虚函数表)虚函数表里的函数有关吧。不知道java底层如何实现的,应该也差不多吧?至于最后那个结果怎么不一样了,我不知道!!!!
只讲解 System.out.println(a2.f(b))其他的都一样了。
首先我们看a2是声明为A的,那么当调用一个方法时,首先他会去查看A中有没有这个方法,现在看到有符合的,即public String f(A obj){return ("A and A");},但是慢着,我们说的多态的意思就是编译器会根据对象的实际型别去调用相应的方法,那么他又发现这个对象的实际型别是B,那么他就去看B类中哪个方法重写了public String f(A obj){return ("A and A");},很明显是public String f(A obj){return ("B and A");},那么输出B and A就理所当然了。个人觉得这么理解简单一点,前面有人讲到方法的调用顺序,我稍微看了一下,没看懂。
C++在调用虚函数时,总是先根据对象的实际类型来寻找。这是标准保证的,也非常适合于Lippman所讲的那种实现方式。
而对Java来说,按照JLS15.12.2节里说的,它会先把可用的函数都列出来,然后再选择。这样当然就会选择到类A的那个成员,因为它的参数列表与传入的参数完全吻合。
a2被向上转型成了A类,所以a2只能调用b.f(A obj),不能调用b.f(B obj)。
现在来看A a1=new B();我只解释一下设计的动机,a1是一个引用(上面有的人看到了),它是要指向A类的对象实体的,现在它指向了B类的对象实体了,但a1的样子依然是A类,它当然只会按照A类的行为及样子来访问B类的方法,这样你就知道为什么a1不能访问B类中添加的新方法和新成员变量,a1只能访问B类中从A类那里继承或重写的方法,注意并不是访问A类的(上面的很多人都错了),因为对象实体是由B类创建的(实体中有B类的任何东西).
注意:可以将a1强制转换成B类的对象如(B)a1,这时a1就可以访问B类的所有属性和功能了.
所以说:同志们哪,基础重要啊!!!
areshank(灰烬的苍鬼) :3)、B中的方法public String f(B obj){return ("B and B");}不存在于A类中,所以a2不会调用这个方法,不会输出"B and B"一句话点醒梦中人啊!谢了!总结一下,一句话:对于多态(例如a2)可以肆无忌惮的当作子类使用(例如b),除了一个区别:a2只能使用父类接口的方法,b则可以使用自己新定义的方法。
1。A a2 (有疑惑的人都是没有透彻的理解到它的意思)
它表示在内存栈中声明一个A类型的对象a2,所以它就“规定”了a2对象只具有class A中定义的两种签名格式的方法。而由于参数b的类型B是A的子类,所以 a2.f(b) 只能匹配到最相近的方法签名 public String f(A obj) ;
可以如下注释掉几行代码,编译看看结果(编译报错,想想为什么???)。
package myExercise.oop;class A{
public String f(D obj){return ("A and D");}
//public String f(A obj){return ("A and A");}
}
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class C extends B{}
class D extends B{}public class TestOverride{
public static void main(String[] args)
{
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
//System.out.println(a1.f(b)); //A and A
//System.out.println(a1.f(c)); //A and A
//System.out.println(a1.f(d)); //A and D
System.out.println(a2.f(b)); //B and A
System.out.println(a2.f(c)); //B and A
System.out.println(a2.f(d)); //A and D
System.out.println(b.f(b)); //B and B
System.out.println(b.f(c)); //B and B
System.out.println(b.f(d)); //A and D
}
}2。= new B();
它表示在内存堆中创建一个B类型的对象,并让a2这个引用指向这个堆中对象的内存地址。由于B中重写了public String f(A obj)方法,所以接下来发生的多态方法调用就很简单了,我相信这一步也难不到大家,关键还是理解第一步的意思。
其次你要知道A{ f(A) f(B) }情况下,a.f(o)如何根据o的类型及f参数的类型进行推导以选择最适当的一个。在Language Spec都有明确规定的,自己查一下就明白了。
super.f(o)
this.f((super)o)
super.f((super)o);
按照这个在看看===
一句中地,C++版也出现同样的题目
在JAVA中,对象变量调用方法调用的肯定是对象实体中的方法(这是理所当然的)而且是与引用类型中一样的方法,知道这一点你就可以解决任何类似的问题.首先你要分析引用是什么类型,那么它就只能调用与类型中一样的方法(因为引用只记住了该类型的样子),然后你要分析对象实体中有什么方法(这非常关键,特别要弄清继承关系),把类型中方法和实体中的方法对照一下,就可以知道a1.f()调用的到底是哪一个方法.
SoftDN.com, 提供免费的项目管理平台:SVN仓库、需求管理、BUG跟踪、任务管理、在线论坛、网站空间、项目存储及完整的备份等。欢迎网友光临建立项目,开创自己的梦想。
地址:http://www.softdn.com http://www.softdn.cn
只讲解 System.out.println(a2.f(b))其他的都一样了。
首先我们看a2是声明为A的,那么当调用一个方法时,首先他会去查看A中有没有这个方法,现在看到有符合的,即public String f(A obj){return ("A and A");},但是慢着,我们说的多态的意思就是编译器会根据对象的实际型别去调用相应的方法,那么他又发现这个对象的实际型别是B,那么他就去看B类中哪个方法重写了public String f(A obj){return ("A and A");},很明显是public String f(A obj){return ("B and A");},那么输出B and A就理所当然了。个人觉得这么理解简单一点,前面有人讲到方法的调用顺序,我稍微看了一下,没看懂。====================================================
这位大侠说的好,就是这么简单的问题,讨论的人多了,反而把问题搞复杂了
A a,b;
a=new A();
b=a;
分析:创建了两个引用变量a,b(我们常说的是声明了两个对象a,b)-->创建一个A类对象实体,用引用a指向它(我们常说的是创建对象a)-->把引用a赋给引用b,也就是使b中存储的值与a中的值相等,这样b也指向了A类的对象实体(我们常说的是把对象a赋给对象b).
对于a.f(),其中的点号是一个运算符,它的功能就是访问a所指向的对象实体中的方法f(),你可以把它理解成一个二元运算符,左边是一个指向某对象实体的引用变量,右边是该对象实体中的f()方法的入口地址.
System.out.println(a2.f(b)); B and A
System.out.println(a2.f(c)); B and A
来说明问题,其他比较简单就不详细阐述。
1、调用哪个类。
在这里很明显a2调用的是A的引用,B类的实例。这里有个规则:引用的类型和实例的类型不一样时,如果出现方法名和字段名相同时,方法调用引用类型的,字段的值是实例类型的。
2、调用类中的哪个接口,这个接口包括方法名和参数,不包括里面具体的实现。
由于a2调用的是A的引用,所以我们只能调用A的接口,在这里A的接口只有两个,即
public String f(D obj)
public String f(A obj)
看上面的输出语句中的参数,b,c都是A类的子类,可以转换为A类的类型,而b,c和D类不存在这种关系,在这里只能选择A中的f(A obj)方法。
3、调用接口的具体实现即我们应该调用引用类型和实例类型中哪个方法中的代码。
这就是方法覆盖的问题,由于a2的引用接口调用的是B类的实例,即B类的代码是在内存中的具体表现,A类的代码没有在内存中实例化,所以A.f(A obj)接口调用的代码是B.f(A obj){return ("B and A");}的代码。