Java基础_面向对象_多态

来源:互联网 发布:华为交换机ip与mac绑定 编辑:程序博客网 时间:2024/05/16 18:16

定义:

某一类事物的多种存在形态
例:动物中猫,狗。
猫这个对象对应的类型是猫类型
猫 x = new 猫();
同时猫也是动物中的一种,也可以把猫称为动物。
动物 y = new 猫();
动物是猫和狗具体事物中抽取出来的父类
父类型引用指向了子类对象
对象,函数都有多态的体现,重点讲对象的多态性。

1、多态的体现

父类的引用指向了自己的子类对象
父类的引用也可以接受自己的子类对象
void function(Animal a)//相当于Animal a = new Cat();

2、多态的前提

必须类与类之间有关系。要么继承,要么实现
还有一个前提就是存在函数的覆盖

3、多态的好处

提高程序的拓展性,可以使用子类覆盖的方法中的特有内容

4、多态的弊端

提高了扩展性,但是只能使用父类的引用访问父类中的成员,不能预先访问子类,因为此时子类还没有对象

5、多态的应用

对类型进行抽取,导致多态的产生,对父类型进行操作,就可以达到操作多个子类型的目的

6、多态的出现代码中的特点(多态使用的注意事项)

在多态中,成员函数(非静态)的特点:

在编译时期,参阅引用型变量所属类型中是否有调用的方法,如果有编译通过,如果没有编译失败。因为编译时还没有创建对象,只能参考父类
在运行时期,参阅对象所属的类中是否有调用的方法。
简单总结就是成员函数在多态调用时编译看左边,运行看右边。
这是因为非静态成员函数有重写的特性

在多态中,成员变量的特点:

当父类子类出现重名变量的时候,无论编译和运行都参考左边(引用型变量所属的类)。因为编译时堆内存中会有两个成员变量,一个父类的,一个子类的,父类引用会先找到父类的成员变量。面试时会考。例:
Fu f = new Zi();
Sop(f.num);//会打印父类的num
Zi z = new Zi();
Sop(z.num);

在多态中,静态成员函数的特点:

无论编译和运行,都参考左边。因为一编译父类和子类两个都加载进内存,静态函数就存在于方法区中的静态区了,静态函数不访问对象中的特有数据,所以不需要new对象,只看引用型变量类中的静态区方法,此为静态绑定。如图所示方法区中的静态区(左)和非静态区(右):


转型

Animal a = new Cat();//类型提升。向上转型(转成父类型)
此时如果想要调用猫的特有方法,比如抓老鼠,就需要向下转型,强制将父类引用转成子类类型
Cat c = (Cat)a;
下面的操作不允许,不能将父类对象转成子类类型,因为不能将一个动物转成猫
Animal a = new Animal();
Cat c = (Cat)a;
我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换
多态自始至终都是子类对象在做着变化,不涉及父类对象

关键字instanceof

判断某一引用数据类型的变量指向的对象属于什么类型的时候,用instanceof关键字,例:
public static void function (Animal a)
{
if (a instanceof Cat)//用于调用对象特有的方法
{
Cat c = (Cat)a;
c.catchMouse();
}

注意判断的时候不要把父类写在前面,否则后面的判断就读不到了

接口和多态

接口的出现降低了耦合性,提高了功能扩展性
接口型引用指向子类对象(多态)也提高了程序扩展性
先定义标准(接口),再按接口扩展程序

主板示例:


interface PCI//PCI是主板和外部设备的总线标准
{

public void open();//注意接口中的方法没有函数体大括号

public void close ();

}
class mainBoard
{

public void run()

{

Sop("mainboard run");

}

public void usePCI(PCI p)

{

if(p!=null)

{

p.open();

p.close();

}

}

}

数据库连接的例子:

Object类

是所有对象的直接或者间接父类
该类中定义的是所有对象都具备的功能

equals方法

Object类中已经提供了对对象是否相容的比较方法,如果自定义类中也有比较相同的功能,没有必要重新定义。只要沿袭父类中的功能,建立自己特有的比较内容即可。这就是覆盖
equals(Object obj)比较的是对象的地址值,相当于==,多态的应用,但是意义不大,所以子类需要覆盖该方法,但是要用到判断和转换的动作
例:
public boolean equals(Object obj)//注意参数类型,这才是覆盖,如果写成子类类型就是重载了
{
if(!obj instanceof Demo)//不同类型相比肯定为假
return false;
Demo d = (Demo)obj;//通过强转为子类类型来访问子类成员,因为Object类中没有该成员
return this.num == d.num;
}

toString方法

返回该对象的字符串表示,例如:
Demo@c17164//类名加对象的哈希值(十六进制)

hashCode方法

返回对象的哈希值(十进制)

getClass方法

返回此Object的运行时类


这些文件都有共性,用Class类来描述图中的class文件

Demo d = new Demo();
Class c = d.getClass();//c指向类文件对象
c.getName();//获取类的名称,这里为Demo