Java多态
一、多态(面向对象的第三个特征)
1、多态—概念
多态:可以理解为事物存在的多种体现形式。
人:男人,女人
动物:猫,狗
猫 x=new 猫();
动物 x=new 动物();//实体x既具备猫的类型也具备动物的类型。
多态的前提:必须是类与类之间有关系。要么继承,要么实现。
多态的体现:父类引用指向子类对象。父类引用也可以接收子类对象。
多态的好处:大大的提高程序的扩展性和代码的复用性。
多态的弊端:只能使用父类的引用去访问被子类复写的父类功能。可以转型。(创建对象时是向上转型,如:Animal a=new Cat(),想调用子类中特有的功能向下转型(强转),如:Cat c=(Cat)a)
2、多态—扩展性
3、多态—转型
用实例来讲解:
/*
动物
猫,狗
*/
一开始:
abstract class Animal
{
public abstract void eat();//吃啥不确定,每个动物 //的事物都不一样。
}
//定义子类
class Cat extends Animal
{
//由子类来实现未知的内容
public void eat()
{
System.out.println(“吃鱼”);
}
//子类自己独有的功能
public void catMouse()
{
System.out.println(“抓老鼠”);
}
}
class Dog extends Animal
{
public void eat()
{
System.ou.println(“吃骨头”);
}
public void kangjia()
{
System.out.println(“看家”);
}
}
class Pig extends Animal
{
public void eat()
{
System.ou.println(“吃饲料”);
}
public void gongdi()
{
System.out.println(“拱地”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
Cat c=new Cat();
c.eat();
Cat c2=new Cat();
c2.eat();
Dog d=new Dog();
d.eat();
Dog d1=new Dog();
d1.eat();
Pig p=new Pig();
p.eat();
Pig p1=new Pig();
p1.eat();
}
}
发现以上主函数中的代码好死板,我们可以:
abstract class Animal
{
public abstract void eat();//吃啥不确定,每个动物 //的事物都不一样。
}
//定义子类
class Cat extends Animal
{
//由子类来实现未知的内容
public void eat()
{
System.out.println(“吃鱼”);
}
//子类自己独有的功能
public void catMouse()
{
System.out.println(“抓老鼠”);
}
}
class Dog extends Animal
{
public void eat()
{
System.ou.println(“吃骨头”);
}
public void kangjia()
{
System.out.println(“看家”);
}
}
class Pig extends Animal
{
public void eat()
{
System.ou.println(“吃饲料”);
}
public void gongdi()
{
System.out.println(“拱地”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
function(new Cat());
function(new Cat());
function(new Dog());
function(new Dog());
function(new Pig());
function(new Pig());
}
pubic static void function(Cat c)
{
c.eat();
}
pubic static void function(Dog d)
{
d.eat();
}
pubic static void function(Pig c)
{
p.eat();
}
}
发现这样的话,如果再来一个动物鸡,那么主类中还需写一个function()以重载形式出现。动物越多,function()重载越多。因此另辟蹊径:
abstract class Animal
{
public abstract void eat();//吃啥不确定,每个动物 //的事物都不一样。
}
//定义子类
class Cat extends Animal
{
//由子类来实现未知的内容
public void eat()
{
System.out.println(“吃鱼”);
}
//子类自己独有的功能
public void catMouse()
{
System.out.println(“抓老鼠”);
}
}
class Dog extends Animal
{
public void eat()
{
System.ou.println(“吃骨头”);
}
public void kangjia()
{
System.out.println(“看家”);
}
}
class Pig extends Animal
{
public void eat()
{
System.ou.println(“吃饲料”);
}
public void gongdi()
{
System.out.println(“拱地”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
function(new Cat());
function(new Cat());
function(new Dog());
function(new Dog());
function(new Pig());
function(new Pig());
}
pubic static void function(Animal a)
{
c.eat();
}
}
但是,这样虽好,却只能调用子类中重写的方法。因此可以向下转型:
abstract class Animal
{
public abstract void eat();//吃啥不确定,每个动物 //的事物都不一样。
}
//定义子类
class Cat extends Animal
{
//由子类来实现未知的内容
public void eat()
{
System.out.println(“吃鱼”);
}
//子类自己独有的功能
public void catMouse()
{
System.out.println(“抓老鼠”);
}
}
class Dog extends Animal
{
public void eat()
{
System.ou.println(“吃骨头”);
}
public void kangjia()
{
System.out.println(“看家”);
}
}
class Pig extends Animal
{
public void eat()
{
System.ou.println(“吃饲料”);
}
public void gongdi()
{
System.out.println(“拱地”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
function(new Cat());
function(new Cat());
function(new Dog());
function(new Dog());
function(new Pig());
function(new Pig());
}
pubic static void function(Animal a)
{
a.eat();
Cat c=(cat)a;
c.catchMouse();//调用了子类自己特有的内容。
}
}
但是,如果传入的是new Dog(),则编译通过,运行失败,发生类型转化异常:ClassCastException。则:
abstract class Animal
{
public abstract void eat();//吃啥不确定,每个动物 //的事物都不一样。
}
//定义子类
class Cat extends Animal
{
//由子类来实现未知的内容
public void eat()
{
System.out.println(“吃鱼”);
}
//子类自己独有的功能
public void catMouse()
{
System.out.println(“抓老鼠”);
}
}
class Dog extends Animal
{
public void eat()
{
System.ou.println(“吃骨头”);
}
public void kangjia()
{
System.out.println(“看家”);
}
}
class Pig extends Animal
{
public void eat()
{
System.ou.println(“吃饲料”);
}
public void gongdi()
{
System.out.println(“拱地”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
function(new Cat());
function(new Cat());
function(new Dog());
function(new Dog());
function(new Pig());
function(new Pig());
}
pubic static void function(Animal a)
{
b.eat();
if(a instanceof Cat)
{
Cat c=(Cat)a;
a.catchMouse();
}
else if(a instanceof Dog)
{
Dog d=(Dog)a;
d.kangjia();
}
else if(a instanceof Pig)
{
Pig p=(Pig)a;
p.gongDi();
}
}
}
上述代码,如果动物越多,判断也就越多,也不是好办法。待留。还有就是不建议在function()中首先对Animal类型做判断,因为无论如何也都成立。
还有就是,将function()单独放在一个类中,这个类与Animal类共同成为一个体系。
4、多态中成员的特点
Fu f=new Zi();(Fu可以是一个类,也可以是一个接口)
(1)在多态中成员函数的特点
1)在编译时期,参阅引用型变量所属的类是否有调用的方法。如果有,编译通过;如果没有,编译失败。
2)在运行时期,参阅对象所属的类中是否有调用的方法。如果有,运行通过;如果没有,运行失败。
简单总结:编译看左边,运行看右边。
(2)在多态中成员变量的特点
无论编译和运行,都参考左边(引用型变量所属的类)
(3)在多态中静态成员变量的特点
无论编译和运行,都参考左边(引用型变量所属的类)
(4)在多态中静态成员函数的特点
无论编译和运行,都参考左边(引用型变量所属的类)
示例1:
/*电脑主板*/
//功能单一的主板逐渐增添多个功能。
一开始
class MainBoard
{
public void run()
{
System.out.println(“mainboard run”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
MainBoard mb=new MainBoard();
mb.run();
}
}
主板功能太单一。现在想上网,买来网卡
class MainBoard
{
public void run()
{
System.out.println(“mainboard run”);
}
public void useNetCard(netCard c)
{
c.open();
c.close();
}
}
//定义网卡
class NetCard
{
public void open()
{
System.out.println(“netcard open”);
}
public void close()
{
System.out.println(“netcard close”);
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
MainBoard mb=new MainBoard();
mb.run();
mb.useNetcard(new NetCard());
}
}
现在又想听音乐,又买来一个声卡,则还得修改主板,耦合性强。发现主板毫无扩展性可言。现在利用多态的思想:
interface PCI
{
Public abstract void open();
Public abstract void close();
}
class MainBoard
{
public void run()
{
System.out.println(“mainboard run”);
}
public void usePCI(PCI p)
{
if(p!==null)
{
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 DuoTaiDemo
{
public static void main(String[] args)
{
MainBoard mb=new MainBoard();
mb.run();
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}
实例2:
/*
数据库的操作:
1、连接数据库。JDBC、Hibernate两种方式
2、操作数据库。c:creat r:read u:update d:delete
3、关闭数据库。
*/
一开始:我们用jdbc的方式连接数据库:
class UserInfoByJDBC
{
public void add(User user)
{
1、JDBC连接数据库。
2、使用sql添加语句添加数据。
3、关闭数据库。
}
public void delete(User user)
{
1.JDBC连接数据库。
2.使用sql删除语句删除数据。
3.关闭数据库。
}
}
class DBOperate
{
public static void main(String[] args)
{
UserInfoByJDBC ui=new UserInfoByJDBC();
ui.add(user);
ui.add(user);
}
}
后来,我们又想通过Hibernate方式连接。则:
class UserInfoHibernate
{
public void add(User user)
{
4、Hibernate连接数据库。
5、使用sql添加语句添加数据。
6、关闭数据库。
}
public void delete(User user)
{
4.Hibernate连接数据库。
5.使用sql删除语句删除数据。
6.关闭数据库。
}
}
class DBOperate
{
public static void main(String[] args)
{
UserInfoByHibernate ui=new
UserInfoByHibernate();
ui.add(user);
ui.add(user);
}
}
发现连接方式和主程序的耦合性非常强。因此利用多态的思想:
interface UserInfoDao
{
public void add();
public void delete();
}
class UserInfoByJDBC implements UserInfoDao
{
public void add(User user)
{
7、JDBC连接数据库。
8、使用sql添加语句添加数据。
9、关闭数据库。
}
public void delete(User user)
{
7.JDBC连接数据库。
8.使用sql删除语句删除数据。
9.关闭数据库。
}
}
Class UserInfoByHibernate implements UserInfoDao
{
public void add(User user)
{
10、Hibernate连接数据库。
11、使用sql添加语句添加数据。
12、关闭数据库。
}
public void delete(User user)
{
10.Hibernate连接数据库。
11.使用sql删除语句删除数据。
12.关闭数据库。
}
}
class DBOperate
{
Public static void main(String[] args)
{
UserInfoDao ui=new UserInfoByJDBC()/
UserInfoByHibernate();
ui.add(user);
ui.delete(user);
}
}
这样,主程序只和interface有关系,与UserInfoByJDBC/UserInfoByHibernate无关。当主程序中还有一个地方需要改,想让它也不用改,则涉及到以后的反射。
2015-11-20至2015-11-20著