java中的多态
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的多态相关的知识,希望对你有一定的参考价值。
java中的多态分为编译时多态和运行时多态,请各位高手帮忙解答一下如何实现,最好附有demo,谢谢。。。
多态包括方法重载和方法重写,说个故事 …… 有点长 …… 可以直接看结论 …… 1.某天, 老板说, 我们的对象都要可以比较! C++程序员写下了 : template< typename T > T max(const T& o1,const T& o2);然后为每个类 添加了 operator< 操作。 Java程序员写下了 : intetface ICompare ... class I_am_exist_with_ONLY_STATIC_METHOD_Because_such_bitch_Java_is_ONLY_OO public: static ICompare max(ICompare o1,ICompare o2) throw(InvalidArgument) ; 然后每个类去implments 一下。 2.过几天, 老板又说了, 我们的对象, 都要可以串行化! C++程序员写了 : template< typename T > void Save(const T& o,Stream& s); void Load(const T& o,Stream& s);然后为每个类实现了一对 Save 和 Load 的函数。 Java 程序员写了 : interface ISerialize void Save(Stream s); void Load(Stream s); 然后为每个类去implments 3.然后又过几天, 再过几天 , 然后…… 每个C++类都有许多函数。每个Java类都 implemts 许多interfaces 4. 然后, 老板怒了, 为什么 max 会throw exception ? Java程序员说 …… String 和 Integer 无法比较 …… C++ 程序员笑了: 编译时我就知道了~~ 5.然后, 老板又怒了, 为什么File里面什么都没有? C++程序员 一看代码: std::vector< Object > v; std::for_each( v.begin() , v.end(), std::bind2nd(ptr_fun(&Save), file ) );坏了 …… 截断了 …… Java程序员笑了: 我早就知道这应该(或者说我们从来用的都)是(运行)多态行为。 这就是区别。 generic programming 和 oo的区别。前者依赖的是concepts, 依赖的是 (昨天写过 忘记在哪了 …… 呆会找找 ) http://bbs.tongji.net/thread-144326-1-1.html (可以直接看10楼, 前面写得很罗嗦…… )后者依赖的是interfaces。 前者的类里面, 更多看到的是 typedef , 相同名字的函数 (push_back, insert ……)因为这就是GP的interfaces —— 在C++GP领域里的专用名词是concepts typedef 和 push_back 没有消耗, 时间或者空间上的 (编译时间如果算的话, 可能还是有点……) 后者的类,就继承自大量的interface。空间上的消耗, 可以C++随便写点什么看看sizeof就知道了, 尤其注意加上 virtual继承后, 编译器塞进去的东西有多大。( 大部分编译器使用的C++的内存模型已经是空间效率与时间效率都非常好的了 —— space : vtbl * classes + vptr *objects , time: O(1) ) 前者的多态仅在编译时, 可以检查出一些不必要的错误(如 int 和string 的比较, 肯定是设计上出了问题), 运行时无多态行为。后者多态在运行时, 有可能会发生一些错误, 以及一点点效率损失。 但是运行多态又是必要的。比如 decorate , 可以处理运行时错综复杂的关系。 编译多态就没辙。 两者各有长处, 完全可以相互取长补短。 故事的最后结局是: C++程序员意识到了错误: 回头看看书 《TC++PL》 “C++是一种通用程序设计语言 …… ” oh yeah!运行多态就运行多态呗, OO就哦哦呗, 咱也行!! struct ISerialize virtual void Save(Stream& s) const = 0; virtual void Load(Stream& s) = 0; public: virual ~ISerialize() /* virtual 是可选的, 决定于是否需要由ISerialize* 删除对象 , 因为下面写了 boost::shared_ptr 所以必须加上virtual 才能多态删除 */ /* 如果不需要多态删除 */ protected: /// /* non-virtual */ ~ISerialize() 然后让每个类实现这个接口。 std::vector<boost::shared_ptr<ISerialize> > v; std::for_each( v.begin() , v.end() , std::bind1st( std::mem_fun(&ISerialize::Save) , file ) );所有对象都写入文件去了。 老板很高兴。 Java程序员盯着满屏幕的 exceptions …… 参考技术A 实现多态的三个条件(前提条件,向上转型、向下转型)1、继承的存在;(继承是多态的基础,没有继承就没有多态)
2、子类重写父类的方法。(多态下会调用子类重写后的方法)
3、父类引用变量指向子类对象。(涉及子类到父类的类型转换)
向上转型 Student person = new Student()
将一个父类的引用指向一个子类对象,成为向上转型,自动进行类型转换。此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,而不是父类的方法此时通过父类引用变量无法调用子类特有的方法。
向下转型 Student stu = (Student)person;
将一个指向子类对象的引用赋给一个子类的引用,成为向下转型,此时必须进行强制类型转换。向下转型必须转换为父类引用指向的真实子类类型,,否则将出现ClassCastException,不是任意的强制转换
向下转型时可以结合使用instanceof运算符进行强制类型转换,比如出现转换异常---ClassCastException 参考技术B 方法的重写和重载是Java多态性的不同表现。
重写是父类与子类之间多态性的一种表现。
重载是一个类中多态性的一种表现。
如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 。
子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。
如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载。
并且重载的方法是可以改变返回值的类型的。
应该能懂了吧
…………我给你解释下多态的意思
多态,我觉得它的作用就是用来将接口和实现分离开,改善代码的组织结构,增强代码的可读性。
以下是我对多态的小结
1. Java中除了static和final方法外,其他所有的方法都是运行时绑定的。在我另外一篇文章中说到private方法都被隐式指定为final 的,因此final的方法不会在运行时绑定。当在派生类中重写基类中static、final、或private方法时,实质上是创建了一个新的方法。
2.在派生类中,对于基类中的private方法,最好采用不同的名字。
3.包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。
4.对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。
5.在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。
6.构造方法是被隐式声明为static方法。
7.用继承表达行为间的差异,用字段表达状态上的变化。
为了给你讲明白,我再给你写端例子
/**
* 定义一个基类
*/
public Class Parents
public void print()
System.out.println(“parents”);
/**
* 定义两个派生类
*/
public Class Father extends Parents
public void print()
System.out.println(“father”);
public Class Mother extends Parents
public void print()
System.out.println(“mother”);
/**
* 测试输出结果的类
*/
public Class Test
public void find(Parents p)
p.print();
public static void main(String[] args)
Test t = new Test();
Father f = new Father();
Mother m = new Mother();
t.find(f);
t.find(m);
参考技术C 呃,看看Thinking in java第四版的泛型部分吧。
Java中的多态
多态:
一、概念:
多态体现为父类引用变量可以指向子类对象。
多态的前提是必须有子父类关系或者类实现接口关系,否则无法完成多态。
在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
定义与使用格式:
父类类型 变量名 = new 子类类型();
变量名.方法名();
普通类多态定义的格式
父类 变量名 = new 子类(); 如: class Fu {} class Zi extends Fu {} //类的多态使用 Fu f = new Zi();
抽象类多态定义的格式
抽象类 变量名 = new 抽象类子类(); 如: abstract class Fu { public abstract void method(); } class Zi extends Fu { public void method(){ System.out.println(“重写父类抽象方法”); } } //类的多态使用 Fu fu= new Zi();
接口多态定义的格式
接口 变量名 = new 接口实现类(); 如: interface Fu { public abstract void method(); } class Zi implements Fu { public void method(){ System.out.println(“重写接口抽象方法”); } } //接口的多态使用 Fu fu = new Zi();
多态的成员特点:
多态成员变量:
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
运行时期:也是调用引用型变量所属的类中的成员变量。
简单记:编译和运行都参考等号的左边。编译运行看左边
多态成员方法:
编译时期:参考引用变量所属的类,如果类中没有调用的方法,编译失败。
运行时期:参考引用变量所指的对象所属的类,并运行对象所属类中的成员方法。
简而言之:编译看左边,运行看右边。
多态-----转型
instanceof 关键字
用instanceof关键字来判断某个对象是否属于某种数据类型(若是根本没关系的话,直接编译失败;编译成功可能为父元素的另外一个子元素)
boolean b = 对象 instanceof 数据类型;
多态本身就是向上转型;
向下转型:必须前提是多态
子类类型 变量名 = (子类类型) 父类类型的变量;
目的:调用子类独有的属性和方法;
转型前:先if(关键字)判断
以上是关于java中的多态的主要内容,如果未能解决你的问题,请参考以下文章