您的位置:首页 > 编程语言 > Java开发

JAVA学习第十五课(多态及其基本应用)

2014-09-22 03:05 495 查看
多态:

面向对象的第三个特征,定义:某类事物存在多种形态,比如,函数就具备多态性,同名的一个函数,它的参数列表不一样,它的存在性就不一样,还有同一个函数,放在父类和放在子类,它的存在性也就不一样。

对象也存在多态性。

例子:动物有猪、猫、狗等

猫这个对象对应的类是猫类

猫 x = new 猫();

同时,猫还是动物的一种,也就可以把猫成为动物

动物 y = new 猫();

动物 z = new 狗();

动物是狗和猫集体事物中抽取出来的父类

父类引用指向了子类对象


一、概述

//对象的多态性
//多态的表现,父类型在指向自对象

class animal
{

}
class cat extends animal
{

}
class dog extends animal
{

}
public class Main
{
public static void main(String[] args)
{
//一个对象两种形态
animal 小动物 = new cat();//小动物通过猫创建对象,动物类在指向
/*
* 猫这类事物具备猫的形态,又具备动物的形态。
* 这就是事物的多态性
* 也就是一个对象对应着不同的类型
* 多态在代码中的体现:
* (父类/接口)的引用指向了其子类的对象
* */
}
}



二、多态的优点

提供了代码的扩展性,前期定义的代码可以使用后期的内容(先有了动物,才有了猪)

以下述代码体现:


abstract class animal
{
abstract void sing();//叫
}
class cat extends animal
{
void sing()
{
System.out.println("喵喵叫");
}
void fun()//猫的特有功能
{
System.out.println("捉老鼠");
}
}
class dog extends animal
{
void sing()
{
System.out.println("汪汪叫");
}
void fun()//狗的特有功能
{
System.out.println("看家");
}
}
class pig extends animal
{
void sing()
{
System.out.println("哼哼叫");
}
void fun()
{
System.out.println("拱地");
}
}
public class Main
{
public static void main(String[] args)
{
//一只猫
cat 小猫 = new cat();
小猫.sing();

//很多猫
cat 二猫 = new cat();
cat 三猫 = new cat();
catqun(二猫);
catqun(三猫);
//....

//多态的体现,多只动物
dog 小狗1号 = new dog();
cat 小猫1号 = new cat();

catqun(小狗1号);
catqun(小猫1号);
catqun(new pig(););
}
static void catqun(animal c)//animal c  = new cat()/dog()/pig();
{
c.sing();
}
}



三、多态的弊端和前提

1.多态的弊端:

前期定义的内容不能使用后期 子类的特有内容


static void catqun(animal c)
{
c.sing();
//	c.fun();->animal里没有fun这个方法
}

PS:当然可以直接使用猫static void catqun(cat c)来调用,但是我们不知道后期到底还会出现多少物种,复用性差

2.多态的前提:

⑴.必须有关系,要么继承,要么实现

⑵.要有覆盖(父类定义了功能,子类具体实现,狗叫、狼叫,很麻烦。犬科叫,很简单)

如果不满足⑵,没有覆盖就使用多态,比如:狗看家,正常,狼看家,这不就出问题了。

保证了多态的这两个前提,就可以提高程序的扩展性

四、转型

以代码体现:


abstract class animal
{
abstract void sing();//叫
}
class cat extends animal
{
void sing()
{
System.out.println("喵喵叫");
}
void fun()//猫的特有功能
{
System.out.println("捉老鼠");
}
}
class dog extends animal
{
void sing()
{
System.out.println("汪汪叫");
}
void fun()//狗的特有功能
{
System.out.println("看家");
}
}
class pig extends animal
{
void sing()
{
System.out.println("哼哼叫");
}
void fun()
{
System.out.println("拱地");
}
}
public class Main
{
public static void main(String[] args)
{//以前指挥对象做事
/*
* cat 小猫 = new cat();
小猫.sing();
*/

animal a = new cat();//自动类型提升,猫对象提升到了动物,类似byte x = 3;int y = x;
a.sing();

//PS:猫一旦提升到了动物,但是其特有功能无法访问。
//专业说法,向上转型。目的:限制对特有功能的访问

//如果还行用猫的特有功能
//就可以将该对象,向下转型
cat c = (cat)a;//将动物a,向下转型为了猫c
c.fun();

// 向下转型的目的:是为了使用子类中特有的方法

/*animal d = new animal();
* animal f = new dog();
*  cat g = (cat)f;
cat e = (cat)d;这种类型不允许,小动物就一定是猫么*/
}
}

注意:对于转型,自始至终都是子类对象在做着类型的转化:猫对象一会转型为动物,一会转型为猫

PS:转型是有目的性

练习:


/*
* BLF和BLF2的故事
* BLF2是BLF的儿子
* */
class BLF
{
void 功能()
{
System.out.println("用C++写程序");
}
void 说英语()
{
System.out.println("hello,world");
}
}
class BLF2 extends BLF
{
void 功能()
{
System.out.println("用java写程序");
}
void 说汉语()
{
System.out.println("你好,世界");
}
}
public class Main
{
public static void main(String[] args)
{
BLF x = new BLF2();//一天BLF2冒充BLF
x.功能();//只能是用java写程序,因为BLF2只会java
x.说英语();//可以,让BLF2像BLF一样,说英语
//x.说汉语();//不可以,BLF2已经向上转型为BLF,禁止了BLF2特有功能的使用
BLF2 Z = (BLF2)x;//变回来
Z.说汉语();
}
}

五、类型判断:

instanceof 用法:

import java.lang.reflect.Method;

abstract class animal
{
abstract void sing();
}
class cat extends animal
{
void sing()
{
System.out.println("喵喵叫");
}
void fun()
{
System.out.println("抓老鼠");
}
}
class dog extends animal
{
void sing()
{
System.out.println("汪汪叫");
}
void fun()
{
System.out.println("看家");
}
}

public class Main
{
public static void main(String[] args)
{
animal BLF = new cat();//猫向上转型为了动物
method1(BLF);
animal BLF2 = new dog();//猫向上转型为了动物
method2(BLF2);
}
public static void method1(animal a)
{
a.sing();
//a.fun();我们知道向上转型后,就无法使用子类特有功能
//所以想要使用就必须再向下转型
cat c = (cat)a;
c.fun();//只是可以的,但是假如我们传一只狗呢
}
public static void method2(animal a)
{
a.sing();
if(a instanceof cat)//instancdof用于判断a的具体类型
//通常是在向下转型前用于健壮性的判断
{
cat c = (cat)a;
c.fun();
}
else if(a instanceof dog)//当然一个父类,有n多子类,不可能写n多if
{
dog c = (dog)a;
c.fun();
}
else if(a==null){System.out.println("类型错误");}
}
}

instaceof 后面可以是类,也可以是接口,且,它只适用于引用数据类型判断


六、多态的成员的特点:(面试。。。。。。)

1.成员变量

2.成员函数

3.静态函数

1.成员变量

编译时,参考引用型变量所属类中是否有调用成员变量,有,编译通过,没有,编译失败

{  为什么编译失败?

假如动物类中没有sing这个方法

animal c = new cat();//把猫提升为动物

c.sing();//猫现在是动物了,但是动物不会sing,所以编译失败  }

运行时,参考引用型变量所属类中是否有调用成员变量,并运行该所属类中的成员变量
简单说:就是编译和运行都参考等号(“=”)左边,fu f = new zi();

见代码://本问题不会在开发中出现,只会在面试时。。。


class fu
{
int num = 3;
}
class zi extends fu
{
int num = 4;
}

public class Main
{
public static void main(String[] args)
{
/* zi z = new zi();
* System.out.println(z.num);//普通继承是先找子类,子类有的直接覆盖
* */
//多态形式
fu f = new zi();//向上转型为了父类
System.out.println(f.num);//3
//想要打印子类的成员变量,向下转型
zi ff = (zi)f;
System.out.println(ff.num);//4
}
}
2.成员函数(非静态函数,重点)

编译时,参考引用型变量所属类中是否有调用的函数,有,编译通过,没有,编译失败

运行时,参考对象所属类中是否有调用的函数,并运行该所属类中的函数
简单说:编译看左边,运行看右边

(非静态函数,需要用对象调用,所以运行时看右边)

class fu
{
void show()
{
System.out.println("父");
}
}

class zi extends fu
{
void show()
{
System.out.println("子");
}
}

public class Main
{
public static void main(String[] args)
{
fu f = new zi();//向上转型将子类型隐藏
f.show();//打印“子”,如果把子类show注释,打印父
}
}

3.静态函数(可以直接用类名调用,比较特殊)

实际上多态性应该没有静态函数,对象的多态性,而静态函数,可以直接用类名调用,创建对象来调用静态方法,这个对象其实就是垃圾

编译时,参考引用型变量所属类中是否有调用的静态方法,有,编译通过,没有,编译失败

运行时,参考引用型变量所属类中是否有调用的函数,并运行该所属类中的函数

简单说:就是编译和运行都看左边


class fu
{
static void my()
{
System.out.println("父sta");
}
}

class zi extends fu
{
static void my()
{
System.out.println("子sta");
}
}

public class Main
{
public static void main(String[] args)
{
fu f = new zi();
f.my();//打印“父sta”,如果删掉父类中的my方法,编译失败
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: