c#和java中的方法覆盖——virtual、override、new
多态和覆盖
多态是面向对象编程中最为重要的概念之一,而覆盖又是体现多态最重要的方面。对于像c#和java这样的面向对象编程的语言来说,实现了在编译时只检查接口是否具备,而不需关心最终的实现,即最终的实现方式是在运行时才会决定。这给强类型语言提供了强大的灵活性,请看下面的例子:
using System; namespace study00
{
class Person
{
public string Name { set; get; }
public virtual void sayHello()
{
Console.WriteLine("Hello. My Name is " + Name);
}
} class Student :Person
{
public override void sayHello()
{
Console.WriteLine("Hello, i am a student. My Name is " + Name);
}
} class Teacher :Person
{
public override void sayHello()
{
Console.WriteLine("Hello, i am a teacher. My Name is " + Name);
}
} class Program
{
static void Main(string[] args)
{
Teacher t = new Teacher();
t.Name = "XiaoMing";
doSomething(t); Student s = new Student();
s.Name = "XiaoMing";
doSomething(s);
} static void doSomething(Person p)
{
p.sayHello();
}
} /* Output:
* Hello, i am a teacher. My Name is XiaoMing
* Hello, i am a student. My Name is XiaoMing
*/
}
在上面这段代码中,doSomething方法需要一个Person类型的对象,但是即使给他传递的是Student类型的对象和Teacher类型的对象,她也能够欣然接受,并根据响应的类型作出正确的处理。我们都知道,这是由于Student和Teacher都继承了Person类,当调用doSomething传递参数时,Student类型的对象发生了向上转型,也称为里氏替换,即父类能够出现的地方,子类一定能够进行替换。所以将Student类型的对象传递给doSomething方法,编译不会出错,而且doSomething方法能够正确执行。这便是面向对象给我们提供的便利,即我们不需要判断某个对象属于什么类型,只要他能够满足给定的要求(这里是继承了Person类),就能够正确运行。

实际上,从更抽象的角度来看,由于每一个类都可以看做某个接口的具体实现,Person可以看做是包含了sayHello()方法的接口的实现。那么我们可以说,Person与它的子类Student和Teacher都是同一个接口的实现,那么我们也就可以理解,doSomething()方法可以正确的处理实现了sayHello()方法的类型。对于doSomething()方法,他不需要知道传递过来的参数是Person类的对象还是它的子类,只要该对象实现了sayHello()方法(继承机制使得子类自动继承了父类的所有方法),那么就可以正确执行。
在上面的代码中,Person中已经有了相应的sayHello()方法的实现,但是当我们运行时却发现,程序运行的却是它的子类的同名方法。这就是所谓的覆盖,即子类隐藏了父类中的同名方法,通过覆盖Person的sayHello()方法,Person的子类实现了自己想要实现的方法,同时又可以向上转型为父类去参与doSomething()方法的运行。也就是说,通过覆盖父类的同名方法,程序实现了运行时的多态。
virtual和override关键字
实现多态时,用到了两个关键字,virtual和override,分别用在父类和子类的签名相同的方法中。什么是签名相同呢?签名相同就是方法同名、参数相同(个数相同、类型相同)、返回值相同。virtual用在父类方法中,表示该方法可以被覆盖。override用在子类的同签名方法中,表示重写了父类的同签名方法。override关键字修饰的的方法必须是和父类的方法是签名相同,而且父类的签名相同的方法必须是被virtual、abstract或者override关键字修饰。
new关键字
我们都知道在c#或java中,创建一个新的对象可以使用new关键字。而在c#中,new还有另一种用法,那就是作为方法的修饰符。new作为方法的修饰符起到了隐藏父类签名相同的方法,在某些情况下起到了和override关键字相同的效果,请看下面的代码:
using System; namespace study001
{
class Person
{
public string Name { set; get; }
public virtual void sayHello()
{
Console.WriteLine("Hello. My Name is " + Name);
}
public void sayBey()
{
Console.WriteLine("Bey");
}
} class Student : Person
{
public override void sayHello()
{
Console.WriteLine("Hello, i am a student. My Name is " + Name);
}
public new void sayBey()
{
Console.WriteLine("Bey, don't forget me!");
}
} class OverrideAndNew
{
static void Main(string[] args)
{
Console.WriteLine("********demo1*********");
Student s1 = new Student();
s1.Name = "XiaoMing";
s1.sayHello();
s1.sayBey(); Console.WriteLine("********demo2*********");
Person p = new Student();
p.Name = "LiHua";
p.sayHello();
p.sayBey(); Console.WriteLine("********demo3*********");
Student s2 = new Student();
Person p2 = s2;
p2.Name = "LaoWang";
p2.sayHello();
p2.sayBey();
}
} /* Output:
* ********demo1*********
* Hello, i am a student. My Name is XiaoMing
* Bey, don't forget me!
* ********demo2*********
* Hello, i am a student. My Name is LiHua
* Bey
* ********demo3*********
* Hello, i am a student. My Name is LaoWang
* Bey
*/
}
在上面代码中的第一个示例中,Student类继承了Person类,并且覆盖了Person类的sayHello()方法,而对于父类中的sayBey()方法,子类中有对应的签名相同的方法,但是没有采用override关键字修饰,而是采用了new关键词修饰,并且父类的对应方法没有采用任何的关键字修饰。在这种情况下,从输出结果中可以看出,子类的对象也成功隐藏了父类的sayBey()方法,采用了自己的实现。这样的情况下,只需要子类的同名方法用new关键字修饰即可,貌似比override更加方便。而且更加重要的是,这个new关键字是可以省略的,也就是说默认情况下,子类的同名方法会隐藏父类的方法。

而从上面的第二个和第三个实例中我们就可以看到new关键字和override关键字的不同之处了。在第二个示例中,采用了父类类型Person的变量引用了子类类型Student的对象。在这种情况下,虽然被覆盖的sayHello()方法依然隐藏了父类的实现,采用了子类的实现,但是对于用new关键字修饰的sayBey()方法,却执行了父类的sayBey()方法。实际上,new关键字的作用是隐藏父类的方法,而并不是覆盖父类的方法。两者的不同就在于覆盖是完全覆盖父类的方法,任何时候通过子类对象都无法获取父类的方法;而隐藏则是在某种情况下是可以通过子类的对象去执行父类的方法的,这种情况就是采用了父类的变量引用了子类的具体对象。同样的,第三个实例和第二个实例相似,都是父类的变量引用了子类的对象,所以执行的都是父类的方法。
java中的方法覆盖
在java中,方法的覆盖要简单的多。子类和父类的同名方法不需要添加任何多余的关键字修饰,只要子类的方法与父类的方法签名相同,子类就会自动覆盖父类的方法。也就是说,java中默认实现了virtual和override关键字。而对于c#中的new关键字,java却没有相应的机制实现。这和c#正好是相反的,c#中如果子类的方法和父类的方法签名相同,则会隐藏父类的方法;java中如果子类的方法和父类的方法签名相同,则会覆盖父类的方法。请看下面的代码:
package study00.override;
class Person {
private String name;
public void sayHello() {
System.out.println("Hello, i am " + this.getName());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student extends Person {
public void sayHello() {
System.out.println("Hello, i am a student, i am " + this.getName());
}
}
public class Program {
public static void main(String[] args) {
Person p = new Student();
p.setName("XiaoMing");
p.sayHello();
}
/**
* Output:
* Hello, i am a student, i am XiaoMing
*/
}
总结
- 多态是面向对象编程中最为重要的概念之一,而覆盖又是体现多态最重要的方面。
- c#中可以采用virtual和override关键字实现方法的覆盖,无法通过子类的对象获得父类的同名方法调用。override修饰的方法只能是父类中被abstract、virtual或者override关键字修饰的方法的同名方法。
- c#中可以采用new关键字修饰来实现隐藏父类的方法,在引用变量和实际对象的类型一致时与override关键字的效果相同,在引用变量是实际对象的父类会执行父类的方法,此时父类的方法不会被覆盖。
- java中默认实现覆盖,但是没有与c#中new关键字效果相同的机制。
c#和java中的方法覆盖——virtual、override、new的更多相关文章
- java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?重写跟重载的区别?
java中的方法重载发生在同一个类里面两个或者多个方法的方法名相同但是参数不同的情况.与此相对,方法覆盖是说子类重新定义了父类的方法.方法覆盖必须有相同的方法名,参数列表和返回类型. 覆盖者可能不会限 ...
- static关键字什么意思?Java中是否可以覆盖一个private或者是static的方法?
答案:“static”关键字表明一个成员变量或者是成员方法可以在没有所属的类的实例变量的情况下被访问.Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译 ...
- JAVA - 请说明”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?
请说明"static"关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法? "static"关键字表明一个成 ...
- java中equals方法和==的用法
java中equals方法的用法以及==的用法(参考一)equals 方法是 java.lang.Object 类的方法.两种用法说明:(1对于字符串变量来说,使用“==”和“equals()”方法比 ...
- Java中的方法内联
Java中的方法内联 1. 什么是方法内联 例如有下面的原始代码: static class B { int value; final int get() { return value; } } pu ...
- Java中,方法的重写、重载的区别,以及多态的实例
首先我们要明白什么是重写和重载 重写(override):子类方法覆盖了父类的方法. (类与类之间继承的关系) 例:父类代码 public class Deng { public void Qi ...
- Java中的方法应用
一.如何定义java中的方法 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 语法: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 public.protected.priv ...
- Java中的方法(形参及实参)return返回类型
如何定义 Java 中的方法 所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 一般情况下,定义一个方法的语法是: 其中: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 pub ...
- 方法重载(overroad)和方法覆盖(override)------java基础知识总结
a.什么是方法重载?(同一个类中)方法重载是指在同一个类中,出现方法名相同,参数列表不同的情况. b.什么是方法覆盖?(子父类中)方法覆盖是指在子类中,出现和父类一模一样的方法声明的时候,会运行子类的 ...
随机推荐
- 剑指offer 复杂链表的复制 (有向图的复制)
时间复杂度O(3N) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...
- php获取Linux网卡信息
$data = exec("/sbin/ifconfig"); var_dump($data); 注意:有时候这种方式获取不到,应该是权限问题 在/var/rootP文件中添加ro ...
- zf-关于查询机把index.jsp换成index_new.jsp页面之后把功能链接都改成新页面的简单方法
一开始我都是找action 然后一个一个的改 把onmousedown="goURL('index.jsp')" 改成 onmousedown="goURL('index ...
- 洛谷U4727 小L 的二叉树
U4727 小L 的二叉树 题目背景 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣. 所以,小L当时卡在了二叉树. 题目描述 在计算机科学中,二叉树 ...
- android脚步---数字时钟和模拟时钟
时钟UI组件是两个非常简单的组件,分为Digitalclock 和Analogclock, main.xml文件,书中程序有问题,加了两个组件,一个Button和一个<Chronometer ...
- 基于Verilog HDL 的数字时钟设计
基于Verilog HDL的数字时钟设计 一.实验内容: 利用FPGA实现数字时钟设计,附带秒表功能及时间设置功能.时间设置由开关S1和S2控制,分别是增和减.开关S3是模式选择:0是正常时钟 ...
- js中的 AOP
原文 :http://blog.csdn.net/notejs/article/details/8770575 面向切面的编程(AOP)还是有点意思的,可以在不修改原有代码的情况下增加新功能.有一些j ...
- php 注意点
1.如果一个方法可静态化,就对它做静态声明.速率可提升至4倍. 2.echo 比 print 快. 3.使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接. 4.在执行for循环之前确定 ...
- LaTeX 多个图片共用一个题注的实现--子图形
http://blog.sina.com.cn/s/blog_58b8951801000a9e.html \begin{figure}\centering\subfigure[这是第一幅图]{\lab ...
- ZenCoding 个人理解和总结
我的理解:ZenCoding是一个html简写的语法,可以最快速的生成html. 不少IDE应该都支持,我用的intellij idea是支持的. ZenCoding表示和CSS/JS有相通之处,比如 ...