多态
可以理解为事物存在的多种体现形态
动物:猫,狗
猫 x = new 猫();
动物 x = new 猫();
---------------------
多态
可以理解为事物存在的多种体现形态
动物:猫,狗
猫 x = new 猫();
动物 x = new 猫();
-----------------------------
多态的体现:
父类的引用指向了自己的子类对象
父类 x = new 子类();
父类是向上抽取的结果,动物 x = new 猫(); new出来的猫具有动物的所有抽象特征
如,猫有动物所具有的吃,睡得抽象特征
但是 猫 x = new 动物();就不行,一个动物对象不一定具有猫的特征
--------------------------------
好处:多态的出现大大提高了程序拓展性
---------------------------------
前提:必须是类与类之间有关系,要么继承,要么实现
还有一个前提,就是存在覆盖,即,父类里面有个吃饭,
但是子类必须覆盖父类的吃饭,如,猫吃鱼,狗吃骨头
---------------------------------
弊端:提高了扩展性,但是只能使用父类的引用访问父类中的成员
public class Test {
public static void main(String[] args) {
Animal a = new Mao();
a.eat();
a.catchMouse();--------------->这句代码是会报错的,因为它是猫特有的
}
}
abstract class Animal{
abstract void eat();
}
class Mao extends Animal{
public void eat(){System.out.println("吃鱼");}
public void catchMouse(){System.out.println("抓老鼠");}
}
-------------------------------------------------
向上转型
-------------------------------------------------------
多态的实例
abstract class Student
{
public abstract void study();
public void sleep()
{
System.out.println("躺着睡");
}
}
————————————————
class DoStudent
{
public void doSome(Student stu)
{
stu.study();
stu.sleep();
}
}
————————————————
class BaseStudent extends Student
{
public void study()
{
System.out.println("base study");
}
public void sleep()
{
System.out.println("坐着睡");
}
}
————————————————
class AdvStudent extends Student
{
public void study()
{
System.out.println(" adv study");
}
}
————————————————
class DuoTaiDemo3
{
public static void main(String[] args)
{
DoStudent ds = new DoStudent();
ds.doSome(new BaseStudent());
ds.doSome(new AdvStudent());
// BaseStudent bs = new BaseStudent();
// bs.study();
// bs.sleep();
// AdvStudent as = new AdvStudent();
// as.study();
// as.sleep();
}
}
先看注释部分,由于基础班和高级班睡觉方式不同,
所以我要分别实例化,并调用学习,睡觉的方法
这样每次都调用学习,睡觉的方法,就会麻烦
那么,此时就可以通过DoStudent类去管理这些事
class DoStudent
{
public void doSome(Student stu)
{
stu.study();
stu.sleep();
}
}
new一个DoStudent,然后调用doSome()方法看,doSome方法参数是Student类型的,
但实例化的时候,我可以new avd,base
Student———>BaseStudent
这样,我就实现了向上转型
------------
上面的好处是什么呢,可以提高拓展性
当我想开设一个黑客班的时候,只需要黑客班继承抽象类
复写抽象类的方法,就可以用DoStudent来实例化了
----------------------------------------------------------------------------------
如下图,zi类继承了fu类的method1,method2方法,并复写了method1方法
现在Fu f = new Zi();
f.method1();
f.method2();
//f.method3(); 如果加上这句,编译会失败的,因为编译看左边,左边是Fu,而Fu类中没有定义method3
而运行看右边,就是说,调用方法时,要看Zi类的方法
所以,上面运行结果是zi method_1;(子类复写的父类)
fu method_2;(子类继承的父类)
---------------------------------------------------
面试题
多态中,成员变量的特点:无论编译和运行,都参考左边
------------------------------------------
-------------------------------------------
参考左边的话,那么打印的第一行就会打印父类的num——>5
第二行就会打印子类的num——>8
----------------------------------------------
多态中,静态成员的特点,都参考左边(静态的方法,变量)
也就是说,子类重写父类的静态方法是不起作用的
---------------------------------------------------
看下面是方法区,里面的是静态方法区,和非静态方法区
--------------------------------------------------------------------------
实例
/*
需求:
电脑运行实例,
电脑运行基于主板。主板上插网卡,声卡,,,,
怎么插呢?通过PCI插槽这个标准
*/
————————————
怎么弄呢
首先,我要有一个主板,并把主板跑起来2
然后,我的主板上要有PCI插槽,所以定义usePCI( PCI p);
而PCI是一个标准,所以是接口
这样,我的主板的PCI插槽里,就可以插声卡,网卡了。。。
那我的声卡,网卡怎么定义呢,要遵循PCI标准,所以要实现PCI接口,并复写接口里的方法
class NetCard implements PCI{
run(){}
close(){}
}
然后看main函数中是怎么跑起来的:
先实例化一个主板,调用run方法让主板跑起来
mb.usePCI(null);//这句代码会出错的,因为这里面是空引用,没有实例(修改后的代码已经有了判断,判断是否为空)
注意:调用usePCI(new NetCard),参数是网卡,但定义的参数是PCI接口,这是怎么回事呢
这是接口型引用指向自己的子类对象,而new的网卡实现了PCI接口(或者说标准)
粗暴点说就是:只要你按照我的标准做(实现接口),你做出来的东西(实例化),就能插进我主板(MainBoard)上的PCI插槽(usePCI)里
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
————————————1
interface PCI
{
public void open();
public void close();
}
————————————2
class MainBoard
{
public void run()
{
System.out.println("mainboard run ");
}
public void usePCI(PCI p) //PCI p = new NetCard()//接口型引用指向自己的子类对象。
{
if(p!=null)
{
p.open();
p.close();
}
}
}
——————————————3
class NetCard implements PCI
{
public void open()
{
System.out.println("netcard open");
}
public void close()
{
System.out.println("netcard close");
method();
}
}
——————————————4
class SoundCard implements PCI
{
public void open()
{
System.out.println("SoundCard open");
}
public void close()
{
System.out.println("SoundCard close");
}
}
————————————————5
class DuoTaiDemo5
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}
———————————————————————————————
实例
看截图,数据库的操作,我刚开始是使用JDBC连接数据库,并添加,删除数据的
可是多年之后,随着技术的发展,出现了新的连接数据库的技术Hibernate
那我可能就要根据需要,把所有的JDBC连接方式全改掉,这样的耦合性(粘性)太高了
那么该怎么办呢
思路是这样的,我可以定义一个标准(接口)UserInfoDao,而JDBC,Hibernate都是遵循这个标准的
这个例子我主要是说实例化的过程
UserInfoDao uid = new JDBC();这种形式
接口 uid = new 类名(); 这个类实现了这个接口
————————————————————
public class ExtendsDemo {
public static void main(String[] args) {
UserInfoDao uid = new JDBC();
uid.add(new User());
uid.delete(new User());
}
}
————————————
class User{
User(){
System.out.println("new user sss");
}
}
————————————
interface UserInfoDao
{
void add(User user);
void delete(User user);
}
————————————
class JDBC implements UserInfoDao{
public void add(User user){System.out.println("JDBC,,,,ADD");}
public void delete(User user){System.out.println("JDBC,,,DELETE");}
}
————————————
class Hibernate implements UserInfoDao{
public void add(User user){System.out.println("Hibernate,,,,ADD");}
public void delete(User user){System.out.println("Hibernate,,,DELETE");}
}
————————————