例子1:
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
public class Demo {
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("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
//结果:
//1--A and A
//2--A and A
//3--A and D
//4--B and A
//5--B and A
//6--A and D
//7--B and B
//8--B and B
//9--A and D
例子2:
class X {
public void show(Y y){
System.out.println("x and y");
}
public void show(){
System.out.println("only x");
}
}
class Y extends X {
public void show(Y y){
System.out.println("y and y");
}
public void show(int i){
}
}
class main{
public static void main(String[] args) {
X x = new Y();
x.show(new Y());
x.show();
}
}
//结果
//y and y
//only x
第二个例子的结果是y and y,为什么第一个例子的第4行打印结果不是“B and B”而是B类里的show(A obj)里的结果?
0
java 执行方法时,是动态匹配的,在运行时才会决定用哪个方法。A ab = new B(); 你调用ab.show(b)时,会根据对象的类型A,去找方法,A中的show(A obj)匹配上,但是此方法在B中被覆盖了,所以会调用B中的show(A obj)。
如果将代码改为:B ab = new B();,这个执行时:ab.show(b)会直接调用show(B obj);ab.show(c)会将c向上转型一次,然后调用show(B obj)。
这样的话最后的结果就会是:
B and B
B and B
总结:
java执行方法时,会根据对象的类型得到相应的方法,如果不存在编译时会报错,真正执行时,会动态去匹配,如果真正的对象是子类的话,且此方法在子类中被覆盖的话,就会执行子类方法。
java类型匹配时,如果不能匹配的话就做向上类型转换,转换为父类,直到能够匹配为止,若一直不能匹配在编译时会报错。
第一个例子属于函数重载,因为a2的类型是A,所以调用show(A obj)。第二个例子属于多态。
a2声明为A类型,A只有show(A obj),没有show(B obj)方法,所以会执行show(A obj),此时调用show(B obj)会报错。因为a2的实际类型为B所以用的B实例的方法 return ("B and A");
如果提前定义了一个方法y(A obj)在y方法中只能用A定义的方法,不能使用A没有定义的方法。否则接口不是没用,框架不是没办法写了。但是A类中方法具体怎么执行就要看你传入的实例了。
你可以在A类中定义一个show(B obj)方法,就有你想好的效果了,或者把A a2 = new B();改成B a2 = new B();
函数重载为在同一作用域下进行的函数操作,而函数重写或者函数覆盖则为父类相应的函数前加上virtual然后子类重写父类函数以实现函数多态。
第二个例子,x是基类,把子类y赋值给基类x。因为子类y重写了基类x的show(Y y)方法,而没有重写show()方法。故子类y赋值给基类x后,x将调用y的show(Y y)方法和x的show()方法。
函数重写或者函数覆盖则为父类相应的函数前加上virtual然后子类重写父类函数以实现函数多态。
关于多态的知识了解一下。
多态时,成员的特点:
1,成员变量。
编译时:参考引用型变量所属的类中是否有调用的成员变量,有,通过编译,没有,编译失败。
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
简单说:编译和运行都参考“=”左边。
作为了解。
2,成员函数(非静态)。****重点****
编译时:参考引用型变量所属的类中是否有调用的函数,有,通过编译,没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
3,静态函数。
编译时:参考引用型变量所属的类中是否有电泳的静态方法。
运行时:参考引用型变量所属的类中是否有调用的静态方法。
简单说:编译和运行都参考“=”左边。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
例一出现这样的原因 是因为有优先级的, B类继承A类,那么他有show(B obj),show(A obj),show(D obj),三个方法
a2.show(b)这个调用,会有show(B obj),show(A obj) 2个方法都满足,但是 A是B的父类,所以优先调用show(A obj)。
你可以这样证明 把B类设置成这样:
class B extends A{
public String show(B obj){
return ("B and B");
}
}
删除B的(A obj) 方法,但是继承了A的(A obj),然后再执行一遍, 看看结果是不是A的(A obj)方法。
如果满意麻烦给个分 急用。。!!
其实是这样的 A a2 = new B(); 这句话执行后, a2 这个对象里 有A类的String show(D obj) 和被B类覆盖的show(A obj)
注意a2 里根本没(B obj)这个方法, 又因为 B继承A 所以会 出现列一 第四行的情况。