[杂文]new 隐藏父类的同名方法

转自http://www.cnblogs.com/IAmBetter/archive/2012/02/22/2363485.html

说隐藏功能的时候,首先要说一下方法表的结构:

内存分为:stack堆栈和heap堆(托管堆)

托管堆:又分为GC堆,GC堆由GC回收器控制内存释放,还分为Load堆,Load堆不受GC回收器控制,当Appdomain卸载时,自动释放内存。

重点说一下Load堆:

Load堆内有 类型表,类型表内有TypeMethod类型方法表:

如下代码:

class F1
    {
        public void S1()
        {
            Console.WriteLine("F1");
        }
    }
    class F2 : F1
    {
        public void S2()
        {
            Console.WriteLine("F2");
        }
    }
    class F3 : F2
    {
        public void S3()
        {
            Console.WriteLine("F3");
        }
    }
如果初始化F3的对象

 static void Main()
        {
            F3 f3= new F3();
        }

内存的分配对应的方法表如图:

 对应的F3类型有一张方法表,对于的F2类型也有一张类型表,对应的F1类型也有一张类型表。

 下面开始重点:

案例1:

class Class1
    {
        static void Main()
        {
            F1 f1 = new F1();
            f1.S();
            F1 f2 = new F2();
            f2.S();
            F1 f3 = new F3();
            f3.S();
        }
    }
class F1
    {
        public void S()
        {
            Console.WriteLine("F1");
        }
    }
class F2 : F1
    {
        public void S()
        {
            Console.WriteLine("F2");
        }
    }
class F3 : F2
    {
        public void S()
        {
            Console.WriteLine("F3");
        }
    }
输出结果: 全部是F1

分析:

1.F1 f1=new F2(); 到底调用那一个S()方法?

调用什么方法,看的不是引用变量的类型,而是看new之后的对象是什么类型,这里是F2类型(),那么就会去找在Load堆F2的类型表,根据F2是继承F1的方法表,当类型表内出现了相同名字的方法的时候,编译器会自动区分,也就是说,此刻F2类型表内,第一个S()方法应该是F1的,第二个才是自己的S()方法,这里有一个”就近原则“,调用第一个方法,也就是F1的S()方法,因为在类型方法表内部:父类方法在子类前面。

//当用子类实例化父类时

// F1 f1 = new F1();

//F1 f2 = new F2();

//F1 f3 = new F3();

//Load堆类型方法表的情况(按顺序)

//F1表 F1.S()

//F2表 F1.S(), F2.S()

//F3表 F1.S(), F2.S(), F3.S()

//当直接实例化子类时

// F1 f1 = new F1();

//F2 f2 = new F2();

//F3 f3 = new F3();

//Load堆类型方法表的情况(按顺序)

//F1表 F1.S()

//F2表 F2.S(), F1.S()

//F3表 F3.S(), F2.S(), F1.S()


因此,根据这个”就近原则“,输出的所有结果都是:F1。

 

案例2:

修改部分代码:

class F2 : F1
    {
        public new void S()
        {
            Console.WriteLine("F2");
        }
    }

 输出结果:还是一样 全部都是 F1。

分析:

new在这里的作用,就是 新建一个与父类方法名一样的方法。

根据我们对 Load堆类型方法表的理解,那么 父类的方法还是在 new出来的子类方法的前面,所以根据就近原则还是调用的F1的S()方法。

 //就是说用不用new关键字修饰,基类方法都会被隐藏,new只是让这步动作合法化而已?

案例3:

class Class1
    {
        static void Main()
        {
            F1 f1 = new F1();
            f1.S();
            F1 f2 = new F2();
            f2.S();
            F1 f3 = new F3();
            f3.S();
            F3 f4 = new F3();
            f4.S();
        }
    }
class F1
    {
        public void S()
        {
            Console.WriteLine("F1");
        }
    }
class F2 : F1
    {
        public  void S()
        {
            Console.WriteLine("F2");
        }
    }
class F3 : F2
    {
        
    }
输出结果:

F1
F1
F1
F2

这里有个注意点:F3 f4=new F3();调用S()方法的时候,如果F3类中有与父类同名的方法,按照就近原则,会先调用自己的S()方法,如果没有,向上查找最近的S()方法,所以输出第一个方法结果是:F2。

 

案例4:

new 真的可以隐藏父类方法吗?new的背后其实就是我们刚才的”就近原则“在作怪,不管new还是不new,父类方法一定是在子类方法前面,回想下Load堆内部的方法表的顺序,就可以理解了。new其实没用隐藏!

那么什么动作会导致父类方法消失呢,就是override,会覆盖父类的方法。

代码如下:

class Class1
    {
        static void Main()
        {
            F1 f1 = new F1();
            f1.S();
            F1 f2 = new F2();
            f2.S();
            F1 f3 = new F3();
            f3.S();
        }
    }
class F1
    {
        public virtual void S()
        {
            Console.WriteLine("F1");
        }
    }
class F2 : F1
    {
        public  override  void S()
        {
            Console.WriteLine("F2");
        }
    }
class F3 : F2
    {
        
    }
输出结果:

F1

F2

F2

分析:

//当用子类实例化父类时

// F1 f1 = new F1();

//F1 f2 = new F2();

//F1 f3 = new F3();

//Load堆类型方法表的情况(按顺序)

//F1表 F1.S()

//F2表 F2.S()  这里F1.S()已经通过override被F2.S()替代,所以不存在F1.S()

//F3表 F2.S()  因为F3无自己的S()方法,所以继承F2的方法表,F2方法表只有F2.S()

//当直接实例化子类时

//同样F3继承F2的表

对于类型F2与类型F3的类型方法表内部,已经没有F1的S()方法了,F3调用S(),就算是就近原则,也是F2的覆盖过的S()方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值