多态
1. 多态的定义:
某种事物的多种体现形式。例如人类中的男人、女人。
男人这个对象对应的类型是男人类型,如:男人 x = new男人();
, 同时男人也是人类中的一种,也可以把男人称为人类。人类 y = new男人();
也可以,父类的引用可以接受自己的子类对象。
2. 多态的前提
类与类之间有关系,还有一个前提就是,存在覆盖,覆盖父类的 功能。
3. 多态的好处
提高了程序的扩展性,但是只有引用访问父类中的成员。
4. 多态的简单应用实例
(1)动物都有基本的 吃饭功能,并且两个对象都有自己的特有功能。建立两个对象猫、狗,它们都有基本的吃饭功能,同时,它们可以有抓老鼠和看门的特有功能。
abstract class Animal
{
abstract void eat();
}
class Cat extends Animal
{
public void eat()
{
System.out.println("eat fish");
}
public static void CatchMouse()
{
System.out.println("Catch Mouse");
}
}
class Dog extends Animal
{
public void eat()
{
System.out.println("eat bone");
}
public void KanMen()
{
System.out.println("KanMen");
}
}
class Demo
{
public static void main(String[] args)
{
Cat c =new Cat();
c.eat();
c.CatchMouse();
Dog d=new Dog();
d.eat();
d.KanMen();
}
}
(2)但是发现上面的程序有一个问题,如果动物太多,程序就不易扩展,所以想到将共同的功能抽取出来单独的进行封装,并使用多态对程序提高程序的扩展性。
但是要注意额是,只能使用父类中的引用访问父类中的成员。也就是说使用了多态,父类型的引用在使用功能时,不能直接调用子类中的特有方法。如:Animal a = new Cat(); (Cat类型提升了,向上转型)。这代码就是多态的体现,假设子类Cat中有特有的抓老鼠功能,父类型的 a就不能直接调用。
如果此时父类的引用想要调用Cat中特有的方法,就需要强制将父类的引用,转成子类类型,向下转型。如:Catc = (Cat)a;但是有一点要注意的是:如果父类可以创建对象,如:Animal a = new Animal(); 此时,就不能向下转型了,Cat c = (Cat)a; 这样的代码就变得不容许,编译时会报错。所以千万不能出现这样的操作,就是将父类对象转成子类类型。
下面就是一个多态的示例:
abstract class Animal//定义父类的功能
{
abstract void eat();
}
class Cat extends Animal//子类Cat继承父类Animal
{
public void eat()//覆盖父类功能
{
System.out.println("eat fish");
}
public void CatMouse()//子类特有的功能
{
System.out.println(" catch mouse ");
}
}
class Dog extends Animal//子类Dog类
{
public void eat()//覆盖父类功能
{
System.out.println("eat bone");
}
public void Kanmen()//子类特有的功能
{
System.out.println("kan men");
}
}
class Demo
{
public static void main(String[] args)
{
Cat c=new Cat();
function(c);
function(new Dog());
}
public static void function(Animal a)
//(Animal a)相当于Animal a=new Cat(); Animal a=new Dog();//向上转型
{
if(a instanceof Cat)//instanceof判断所属类型
{
a.eat();
Cat c=(Cat)a;//向下转型
c.CatMouse();
}
else if (a instanceof Dog)
{
a.eat();
Dog d=new Dog();//向下转型
d.Kanmen();
}
}
}
5.多态的成员变量特点
(1)非静态的成员函数
编译时的注意事项:参阅引用型变量所属的类(父类)中是否引用的方法,有则通过编译没有 则不能 通过。(简单点的描述:多态时编译看左边,运行看右边)。
举例说明:
class Fu
{
void method1()
{
System.out.println("Fu method1");
}
void method2()
{
System.out.println("Fu method2");
}
}
class Zi extends Fu
{
void method1()
{
System.out.println("Zi method1");
}
void method3()
{
System.out.println("Zi method2");
}
}
class Demo
{
public static void main(String[] args)
{
Fu f=new Zi();
f.method1();//覆盖父类的方法
f.method2();//使用父类中的函数方法
//f.method3();如果有此句的情况下,不能通过编译;参阅引用型变量所属的类(父类)中是否有引用的方法(编译看左边,运行看右边)
}
}
(2)对于成员变量的特点
无论编译和运行,都参考左边(引用变量所属的类)。如:多态中的父类引用调用成员变量时,如果父类和子类有同名的成员变量,那么被调用的是父类中的成员变量。
class Fu
{
int num=1;
}
class Zi extends Fu
{
int num=2;
}
class Demo
{
public static void main(String[] args)
{
Fu f=new Fu();
System.out.println(f.num);
Zi z=new Zi();
System.out.println(z.num);
}
}
结果为:
(3)对于静态的成员函数(和成员变量一样打印的是左边)
class Fu
{
static void method1()
{
System.out.println("Fu method1");
}
}
class Zi extends Fu
{
static void method1()
{
System.out.println("Zi method1");
}
}
class Demo
{
public static void main(String[] args)
{
Fu f=new Zi();
f.method1();//静态成员变量查看左边
}
}
6.多态的主板实例
让主板通过PCI来使主板和网卡、声卡的相互连接
//定义接口
interface PCI
{
public void open();
public void close();
}
class MainBoard
{
public void run()
{
System.out.println("MainBoard Run");
}
/*多态的应用,提高了程序的扩展,相当于 PCI p=new SoundCard();
PCI p=new NetCard();*/
public void UsePCI(PCI p)性
{
p.open();
p.close();
}
}
//网卡驱动
class NetCard implements PCI
{
public void open()
{
System.out.println("NetCard open");
}
public void close()
{
System.out.println("NetCard close");
}
}
//音频驱动
class SoundCard implements PCI
{
public void open()
{
System.out.println("SoundCard open");
}
public void close()
{
System.out.println("SoundCard close");
}
}
class Demo
{
public static void main(String[] args)
{
MainBoard mb=new MainBoard();
mb.run();
mb.UsePCI(new NetCard());
mb.UsePCI(new SoundCard());
}
}
7.object类
(1)Object类是所有对象的直接或间接父类。本身具有很多类或者是方法
//相当于里面隐含的构造函数为super()即Object()
class Demo extends Object
{
Demo()
{
super();
}
}
class ObjectDemo
{
public static void main(String[] args)
{
Demo d1=new Demo();
Demo d2=new Demo();
Demo d3=d1;
System.out.println(d1.equals(d2));
System.out.println(d1.equals(d3));//其实比较的是地址
}
}
(2)想建立自己的Demo类的比较方式来比较Demo的特征,则需要自己来定义功能
class Demo
{
private int num;
Demo(int num)
{
this.num=num;
}
//自己定义函数的功能,定义compare函数
public boolean compare(Demo d)
{
return this.num==d.num;
}
}
class ObjectDemo
{
public static void main(String[] args)
{
Demo d1=new Demo(4);
Demo d2=new Demo(5);
System.out.println(d1.compare(d2));
}
}
(3)但是父类已经有了比较功能的功能函数equals,没必要重新定义,只要沿袭父类的功能就可以了
class Demo
{
Demo(int num)
{
this.num=num;
}
//复写equals原来的功能,不用重新定义新的函数
public boolean equals(Object obj)
{
return this.num=obj.num;
}
}
class ObjectDemo
{
public static void main(String[] args)
{
Demo d1=new Demo(4);
Demo d2=new Demo(5);
System.out.println(d1.equals(d2));
}
}