最近温习了一下面向对象程序设计的基本知识,做了个小小的实验:
以下为c#代码:
public class TestParameterFather { } public class TestParameterSon : TestParameterFather { } public class TestClassFather { public void TestMethod(TestParameterSon p) { } } public class TestClassSon : TestClassFather { public void TestMethod(TestParameterFather p) { } }
以下为Java代码
public class TestParameterFather { } public class TestParameterSon extends TestParameterFather { } public class TestClassFather { public void TestMethod(TestParameterSon p) { } } public class TestClassSon extends TestClassFather { public void TestMethod(TestParameterFather p) { } }
调用方法:
TestClassSon father = new TestClassSon(); father.TestMethod(new TestParameterSon());
结果发现在 c#里面这个 TestMethod 调用的是TestClassSon 里的TestMethod,而在java里面调用的是TestClassFather里的TestMethod,如果按照里氏替换原则来说,应该调用TestClassFather的TestMethod才对,就是说c#里面是错误的,难道说jvm和clr对于面向对象的这种调度机制不一样么
你自己搞混淆了吧?如果就看这样的代码
public class TestClassFather
{
public void TestMethod()
{ }
}
public class TestClassSon : TestClassFather
{
public void TestMethod()
{ }
}
你觉得应该调用谁的TestMethod()?再看看如下代码的结果,你这个问题是继承的问题,不要把其它的因数加进来,会把自己搞晕
namespace ConsoleApplication2 { class Program { static void Main(string[] args) { TestClassFather TF = new TestClassFather(); TestClassSon TC = new TestClassSon(); TestClassFather TK = new TestClassSon(); TF.TestMethod(); TC.TestMethod(); TK.TestMethod(); TestClassFather1 TK1 = new TestClassSon1(); TK1.TestMethod(); } public class TestClassFather { public void TestMethod() { Console.WriteLine("父类TestMethod被调用"); } } public class TestClassSon : TestClassFather { public void TestMethod() { Console.WriteLine("子类TestMethod被调用"); } } public class TestClassFather1 { public virtual void TestMethod() { Console.WriteLine("父类TestMethod被调用"); } } public class TestClassSon1 : TestClassFather1 { public override void TestMethod() { Console.WriteLine("子类TestMethod被调用"); } } } }
你搞错了吧。java不是这样的,看花眼了。
其实这个我是在看设计模式之禅的时候发现书上是这么描述的(java描述)然后我试了一下,确实发现有这种区别,书上描述的是会调用父类的Method。按照里氏替换原则的话应该是按java这样的。
@zxding1986:
你确实打错了,应该是
TestClassFather father = new TestClassSon(); father.TestMethod(new TestParameterSon());
@angelshelter:
TestClassSon father = new TestClassSon(); father.TestMethod(new TestParameterSon());
就是这么用啊,为什么一定要用父类去引用。
@zxding1986: 扩展性强。
按照里氏替换原则 子类跟 父类有同名方法,会隐藏父类方法,C#的显示就是正常的,正是符合里氏替换原则的后果,只是不建议这样用。
java不懂,不知道你的java代码是怎么搞得,既能无法访问自己的方法,那访问子类自己的方法,又该怎么办呢?
子类的入参应该宽于父类的同名参数吧,这样的话应该调用的是父类的方法。所以c#这样应该是不符合的的
我还是觉得c#这样是不对的,因为这样相当于我在没有override父类的方法的情况下居然子类的方法被调用了,这样违背了里氏替换原则吧。
@zxding1986:
里氏替换 原则告诉我们 不要这样写,你这样写 同名函数 是违背里氏替换原则。
但是 既能 你这样写了,就会隐藏父类函数,这也正是 里氏替换 告诉我们的后果,执行结果 也是如此。
我相信 java 也会隐藏 父类的同名函数,要不然就 没有这个原则了,这个原则 就是提醒我们这个(不要隐藏 父类的同名函数,而不是 虚拟机来实现的,是 我们编程代码不要这样去做)。
晕了!!!!
你自己搞错了。Java的方法不加关键字默认都是虚方法(即C#里的virtual关键字),而C#的方法不加关键字默认不是虚方法。因此这里跟里氏替换原则没有关系。
这个应该是正解了。我用c#比较少,确实是virtual的原因。