< 示例1>
1 class Base {
2 int x = 2 ;
3 int method() {
4 return x;
5 }
6 }
7
8 class SubClass extends Base {
9 int x = 3 ;
10 int method() {
11 return x;
12 }
13 }
14
15 public class Main {
16 public static void main(String[] args) {
17 Base b = new SubClass ();
18 System.out.println(b.x);
19 System.out.println(b.method());
20 }
21 }
2 , 3
<练习>
1 class s1 {
2 public String s = " s1 " ;
3 public String get() {
4 return s;
5 }
6 }
7 class s2 extends s1 {
8 public String s = " s2 " ;
9 public String get() {
10 return s;
11 }
12 }
13 public class s {
14 public static void main(String[] args) {
15 s1 a = new s2();
16 System.out.println(a.s);
17 System.out.println(a.get());
18 }
19 }
这个地方就是多态的一个陷阱;
多态是对方法而言的,不是对变量;
s1 a = new s2();这里生成的对象是s1类的实例,但是是由s2类构造的;
java中对变量的选择是静态的,对方法的选择是动态的,是在运行时决定的。(static除外)
运行时实际上调用的是实例的方法,即s1的方法;但对于继承(多态的一种方式),方法的定位是在动态执行时选择的,选择实际构造者,因此就出现了本题的现象了。
另外:多态是对方法而言的,不是对变量;这样说有些不严密,方法应该有个修饰,就是除了final修饰的方法外,java中对函数的调用都是后期绑定,所谓的后期绑定就是动态选择
摘自 崔毅解答csdn疑问时给出的分析
注意以下的方法都被修饰了final
< 示例2>以下哪里会出错?
1 class Base {
2 private final void f() {
3 System.out.println( " Base.f() " );
4 }
5 }
6
7 class Derived extends Base {
8 public final void f() {
9 System.out.println( " Derived.f() " );
10 }
11 }
12
13 public class Main {
14 public static void main(String[] args) {
15 Derived op1 = new Derived();
16 Base op2 = op1;
17 op1.f();
18 op2.f();
19 }
20 }
21
op2.f(); 处出错!
<示例3>
1 class Parent {
2 private void method1() {
3 System.out.println( " Parent's method1() " );
4 }
5 public void method2() {
6 System.out.println( " Parent's method2() " );
7 method1();
8 }
9 }
10 class Child extends Parent {
11 public void method1() {
12 System.out.println( " Child's method1() " );
13 }
14 public static void main(String args[]) {
15 Parent p = new Child();
16 p.method2();
17 }
18 }
1 答案是:prints: parent’s method2() parent’s method1()
2 如果把父类中method1改成public,那么答案是
3 prints: parent’s method2() child’s method1()
分析
多态:
Java 中的函数,除了声明外 final 的外,都是后期绑定。
所谓绑定是建立“函数调用”和“函数本体”的关联。、
所谓的后期绑定是指执行时根据对象类别而进行
多态仅仅对函数而言,不对变量而言;
变量的访问依赖于编译期引用指向的类型;
方法的访问依赖于执行期对象的类型;
向上转型后,调用某个函数,若 derived class overriding 了该函数,则会调用该 derived class 中的函数,否则会调用 base class 中的函数。
向上转型后,只能调用 base class 中被 derived class overriding 的函数,不能调用 derived class 中 extend 函数。
即向上转型后,只能调用 base class 中的方法,不能调用 derived class 中的扩展方法
1 public class CalC {
2 void amethod() {
3 System.out.println( " CalC.amethod " );
4 }
5 CalC() {
6 amethod();
7 System.out.println( " Hu? " );
8 }
9 public static void main(String[] args) {
10 CalC cc = new CalChild();
11 cc.amethod();
12 }
13 }
14 class CalChild extends CalC {
15 void amethod() {
16 System.out.println( " CalChild.amethod " );
17 }
18 }
1 output:
2 CalChild.amethod
3 Hu ?
4 CalChild.amethod
5 为什么CalC Constructor调用的不是自己的amethod()呢
1 方法在内存中只有一个备份,所以的对象都共享这个备份,为了区分开到底是哪个对象在调用这个方法,关键的地方就是this的使用。this把调用方法的上下文对应到当前对象上。
2
3 第二,调用java中的所有成员变量或者成员函数都隐含了this。
4
5 所以这个地方就很明了了:构造子类,this指针代表的当前对象是子类实例,子类实例为啥不调用自己overriding的方法呢?!
6
--------取于 崔毅 之《java编程指南》《java编程思想》学习笔记l
以下是强化和复习:
1 多态只针对非final方法;
不针对变量、final方法
2方法[非final]是运行时对应对象
变量、fianl是编译期间对应对象
3多态只能调用父类中有的方法(向上扩展后)
不能调用父类中没有的方法;
不能调用子类中扩展父类[not overridding]方法
4多态定义:指的是使用同一个实现接口,以实现不同的对象实例
多态好处:多态让程序依赖接口或者抽象类,而不是具体类
p.s
1class Base {
2 int x = 2 ;
3 String s="s1";
4 int method() {
5 return x;
6 }
7 public String method2(){
8 return s;
9 }
10 }
11 class SubClass extends Base {
12 int x = 3 ;
13 String s="s2";
14 int method() {
15 return x;
16 }
17 public String method2(){
18 return s;
19 }
20}
21public class t4 {
22
23 public static void main(String[] args) {
24 Base b = new SubClass ();
25 System.out.println(b.x);
26 System.out.println(b.method());
27 System.out.println("-----用new SubClass会如何?------");
28 System.out.println(new SubClass().x); //相当于 SubClass a=new SubClass(); 然后a.x
29 System.out.println(new SubClass().method());//相当于a.method();
30 System.out.println(new SubClass().s);
31 System.out.println(new SubClass().method2());
32 System.out.println("-----直接new SubClass的test结束------");
33 System.out.println(b.s);
34 System.out.println(b.method2());
35
36
37 }
38
39}
40
12
23
3-----用new SubClass会如何?------
43
53
6s2
7s2
8-----直接new SubClass的test结束------
9s1
10s2
11
这说明直接写new son();//相当于 son son=new son();
2 int x = 2 ;
3 String s="s1";
4 int method() {
5 return x;
6 }
7 public String method2(){
8 return s;
9 }
10 }
11 class SubClass extends Base {
12 int x = 3 ;
13 String s="s2";
14 int method() {
15 return x;
16 }
17 public String method2(){
18 return s;
19 }
20}
21public class t4 {
22
23 public static void main(String[] args) {
24 Base b = new SubClass ();
25 System.out.println(b.x);
26 System.out.println(b.method());
27 System.out.println("-----用new SubClass会如何?------");
28 System.out.println(new SubClass().x); //相当于 SubClass a=new SubClass(); 然后a.x
29 System.out.println(new SubClass().method());//相当于a.method();
30 System.out.println(new SubClass().s);
31 System.out.println(new SubClass().method2());
32 System.out.println("-----直接new SubClass的test结束------");
33 System.out.println(b.s);
34 System.out.println(b.method2());
35
36
37 }
38
39}
40
23
3-----用new SubClass会如何?------
43
53
6s2
7s2
8-----直接new SubClass的test结束------
9s1
10s2
11