
Java中的多态允许父类指针指向子类实例。如:Father obj=new Child();(其中Child是Father的子类)。这样就产生了一个问题——
使用这个父类型的指针访问类的属性或方法时,如果父类和子类都有这个名称的属性或方法,哪一个属性或方法会被调用呢?
最好的办法是实验:
class Father
{
int r;
Father()
{
r=4;
}
void printname()
{
Systemoutprintln("I’m father");
}
}
class Child extends Father
{
int r;
Child()
{
r=5;
}
void printname()
{
Systemoutprintln("I’m Child");
}
}
public class Test
{
public static void main(String[] args)
{
Father obj=new Child();
Systemoutprintln(objr);
objprintname();
}
}
结果输出:
4
I’m Child
实验证明。属性会访问父类的。方法分访问子类的。
这就是多态了。
不要以为Father obj=new Child();这条语句一定会让objprintname()指向Chlid定义的printname()。实际上,如果你把Father类中的printname()方法删除,这个程序将编译失败。因为Father中的并没有定义printname()这个函数。多态是晚绑定(见本文最后的资料)的,在Father obj=new Child();这个语句中,如果Father中没有printname()这个函数,就不会为obj建立一个用于调用printname()函数的指针。所以调用objprintname()会出错。如果Father中有这个函数。指向printname()函数的指针会被创建。在调用objprintname()时,不会出错,而且,因为obj指向的是new Child(),是个Chld类的实例。所以调用objprintname()时调用了Child类中定义的printname()。这就是方法的动态绑定。
那么,刚才说到把Father类中的printname()方法删掉后,obj将无法调用Child类中的printname(),因为objprintname()会编译失败。那么如果我就是需要调用要怎么办呢?其实虽然obj是Father类型的,但是它指向的是一个Child类的实例。那么可以将obj强制类型转换为Child。再调用printname()方法就可以了。
在上面程序中,把Father类中的printname()方法整个删掉,再将objprintname() 改成 ((Child)obj)printname()后,编译成功,结果输出:
4
I’m Child
两次输出的结果都是I’m Child。
那么如何可以运行Child类中的printname()来输出“I’m Father”呢?
其实只需要将Father obj=new Child();改成Father obj=new Father();就可以了,呵呵。另一个办法就是将Child类中定义的printname()整个删掉。为什么这样可以成功呢?自己想想,嘿嘿。最后会有个这样的思考题。
看到这儿你可能早就想问了:
为什么objr是4?为什么不是5?
呵呵。其实很简单。Java中的多态仅为方法而言,成员变量还是使用的父类的成员变量。也就是说,因为“Father obj =……”,所以obj是Father类型的,所以obj里面的r是Father里面的r,所以输出objr就是4了。
你又想问:
那么5去哪了?new Child()的时候,不是会把5放到Child的r中吗?
实际上5还是有的。只是objr是4而已。想访问Child中的r,把5读出来,可以这样写:
((Child)obj)r
就是把obj由Father型强制转换成了Child型。
OK,方法和属性在多态中是什么样的你都清楚了。现在做个题测试一下吧:
这是J@Whiz14的一道题:
class Base {
int i = 99;
public void amethod() {
Systemoutprintln("Baseamethod()");
}
Base() {
amethod();
}
}
public class Derived extends Base {
int i = -1;
public static void main(String argv[]) {
Base b = new Derived();
Systemoutprintln(bi);
bamethod();
}
public void amethod() {
Systemoutprintln("Derivedamethod()");
}
}
会输出什么?
先想想,再看答案:
答案:
========================
Derivedamethod()
99
Derivedamethod()
========================
讲解:
这个程序的执行过程是这样的:
第一行:Base b=new Derived();
执行这一行语句的过程中,要构造Derived这个类,而它有父类Base,所以先构造Base类。构造Base类的默认构造函数有定义。内容是执行amethod()方法。
实际上,Base类构造方法中的执行amethod(),相当于执行thisamethod(),在这个程序中,就相当于执行bamethod()。而b是Base类型的,指向了Derived类的实例的指针。所以跟据上面我们的总结,实际上执行的是Derived类的amethod()函数。所以,第一行“Base b=new Derived();”执行完,输出"Derivedamethod()"。
第二行:Systemoutprintln(bi);
这个很简单,成员变量,不考虑多不多态,只看它定义时前面的类型。这个程序中是Base b,所以bi就是Base类中的i。输出99
第三行:bamethod();
调用Derived类中的amethod()方法。
其实这行就是迷惑你的,如果没有这一行。你可能会警觉起来——咦?为什么这儿定义一个amethod()呢?没有地方调用它啊?
有了这行代码,就会使你放松警惕。觉得,啊。定义了这个是用来让bamethod();调用的。
首先,多态存在的三个必要条件
一、要有继承;
二、要有重写;
三、父类引用指向子类对象。
多态引用类型有两种方式:
a 编译时多态:方法的重载;
b 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态。(我们平时说得多的事运行时多态,所以多态主要也是指运行时多态);
多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
多态有两种表现形式:重载和覆盖
首先说重载(overload),是发生在同一类中。与什么父类子类、继承毫无关系。
标识一个函数除了函数名外,还有函数的参数(个数和类型)。也就是说,一个类中可以有两个或更多的函数,叫同一个名字而他们的参数不同。
他们之间毫无关系,是不同的函数,只是可能他们的功能类似,所以才命名一样,增加可读性,仅此而已!
再说覆盖(override),是发生在子类中!也就是说必须有继承的情况下才有覆盖发生。
我们知道继承一个类,也就有了父类了全部方法,如果你感到哪个方法不爽,功能要变,那就把那个函数在子类中重新实现一遍。
这样再调用这个方法的时候,就是执行子类中的过程了。父类中的函数就被覆盖了。(当然,覆盖的时候函数名和参数要和父类中完全一样,不然你的方法对父类中的方法就不起任何作用,因为两者是两个函数,毫不关系)
1 public class Animal
2 {
3 public void bite()
4 {
5
6 }
7
8
9 public static void main(String args)
10 {
11 Animal A = new Cat();
12 Animal B = new Dog();
13
14 Abite();
15 Bbite();
16 }
17
18 }
19
20
21 class Cat extends Animal
22 {
23 public void bite()
24 {
25 Systemoutprintln("MiaoMiao is bitting");
26 }
27 }
28
29
30 class Dog extends Animal
31 {
32 public void bite()
33 {
34 Systemoutprintln("WangWang is bitting");
35 }
36 }
假设有一个类 叫 鸟类,它拥有属性翅膀,拥有方法鸣叫,如下
public class Bird{
private Wing wing;
public void moo(){
Systemoutprintln("鸟叫声");
}
}
鸟类封装了 翅膀类和moo方法;另外有两个类都继承鸟类并重写了moo方法,分别是鹦鹉和麻雀如下:
鹦鹉类:
public class Parrot extends Bird{
public void moo(){
Systemoutprintln("鹦鹉的叫声");
}
}
麻雀类:
public class Sparrow extends Bird{
public void moo(){
Systemoutprintln("麻雀的叫声");
}
}
方法重写应该懂吧,不懂自己找书看吧;然后你有个妻子她想听鸟叫,就有个妻子类
public class Wife{
public void listen(Bird bird){
birdmoo();
}
/这时多态就很好的体现了,你妻子想听鸟叫,无论什么鸟都可以给她,但是你想让她和鹦鹉
说话,你就买了一只鹦鹉传给listen方法,结果你妻子听到了鹦鹉的叫声,程序输出:鹦
鹉的叫声
/
public static void main(String[] args) {
new Wife()listen(new Parrot());
}
}
多态实现了动态绑定,让程序有了很好的扩展性,比如你以后想买一只燕子送给你妻子,就只需要写个燕子类Swallow继承Bird方法就可以了,而不需要再在妻子类里添加一个方法listen(Swallow swallow)……上面编码没用编译器,可能有错误,请谅解
说得够详细了吧,感谢世界上有我这么好的人吧 ^_^
加减乘除很简单,对数需要用到Java的计算类Math
举个多态的例子
public static int add(int a,int b){
return a+b;
}
public static double add(double a,double b){
return a+b;
}
public static String add(String a,String b){
return a+b;
}
同样一个方法被调用,如果参数的类型不同,那么返回的结果接不一样,这样就体现了面向对象的多态的特点,这里用到的多态中的重载
啊,这个也叫多态么,我怎么只看出了派生和继承。那同一个对象的多个实例产生的差异怎么会被叫做多态呢。。。。可惜我的JAVA还没入门,呵呵,我查查看。
抄一段,看这个说的还算明白,至少我能看出多态的存在,只是跟C++里的概念似乎不太一样。
重载是编译期的多态,重写是运行期的多态。
public
class
Base{
int
a,b;
public
Base(int
x,int
y){
a
=
x;
b
=
y;
}
public
int
add(){
return
(a
+
b);
}
public
void
add(int
x,int
y){
int
z;
z
=
x
+
y;
}
}
上面这段代码就是重载~~~他有三个特征
1:方法名必须一样
“add()“。
2:返回类型可以不一样
就象是
”int
“和”void“
3:参数可以不一样
就是add()
和add(int
x,int
y)这样的。
public
class
Base{
int
x,y;
public
void
add(){
int
z;
z
=
x
+
y;
}
}
public
class
Child
extends
Base{
int
x,y;
public
void
add(){
int
z;
z
=
x
+
y;
}
public
static
void
main(string
[]
args){
Base
b
=
new
Child();
badd();
}
}
下面这个例子就是重写,他实现了多态~~
重写的要求是,方法名必须一样,返回类型必须一样,传入的参数必须一样
在main函数中定义父类的对象,但是用子类去实例化他,这样就可以通过父类的对象调用到子类的方法。如果你不能完全理解多态的话,
这样Base
b
=
new
Base()
Child
c
=
new
Child()
b
=
c
这样的话,你应该好理解多了~~
我明白了,不知道LZ什么感觉。。
以上就是关于java中的多态 到底怎么使用全部的内容,包括:java中的多态 到底怎么使用、java实现多态有几种方式分别是什么、java中的多态等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)