Java之多态

Posted on 2017-03-09 21:50  future_liu  阅读(166)  评论(0编辑  收藏  举报

Java的第三大特性--------》多态

一、什么是多态

  多态根据其字面意思就是多种形态的意思,那么在Java中的多态指的是什么呢?

       指的是对象具有多种形态的意思,只是Java中分为引用多态和方法多态

   A.引用多态

     a.父类的引用指向本类的对象

   b.父类的引用指向子类的对象

如下图所示可以看出来,父类Animal_manStyle的引用指向了本身,还可以指向子类的对象,

但是子类的引用不可以指向父类的对象。   这就好比猫是动物,但动物不一定是猫啊

 

 

 

 

 

  B.方法多态

         a.父类的对象可以调用本身的方法

    b.父类指向子类的对象,那么调用的时候就是调用的子类的方法(子类重写了父类的方法),如果子类没有重写父类的方法,那么子类对象调用的就是父类的对象

如上图的调用,a是父类的对象引用,c是子类的对象引用,结果如下

 

            注意:多态是基于继承的,但是有一种情况下是不能使用多态的,便是父类指向的引用不能指向子类独有的方法

 

二、多态之引用类型转换

  引用类型转换分为两种转换,一种是自动类型转换,二是强制类型转换

   A.自动类型转换又称为向上类型提升

    

Bus类是Transportation的子类,即 父类的引用可以指向其子类(小类型转换成大类型),上图就是自动类型转换。

   B.强制类型转换又称为向下类型转换,存在一定的风险      

            

          

  上图可以看出来,当一个父类型的引用指向一个子类型的对象时,可以对其进行强制类型转换,为了避免类型转换时出现的不安全为问题,我们利用 instanceof关键字,instanceof关键字是判断这个引用是否是这个类的,即 car 引用是否是Car类型的或者是Car的子类型的,当if中的判断成立的话,我们就可以进行强制类型转换,并且不会出错。

  其实强制类型转换的根本就是,当利用构造器构造出来的对象在内存中本身已经有一个类型,如果要赋予的引用是这个类型的或者是其父类型的则可以进行强制类型转换,如

            Animal  animal = new Dog();

    Dog  dog=(Dog)animal;

animal 在内存中本身就是Dog类型的,所以对其进行强制类型转换成Dog是可以的

但是,

  Animal animal = new Animal();

  Dog dog = (Dog) animal;

这个是不行的,因为animal 在内存中本身是Animal 类型的,现在对它进行的转换不是它本类,或者是它的父类,所以这个是不可以进行类型转换的,编译器会通过,但是运行时会抛出ClassCastException异常

同样还有一种情况是不可以的,如下:

  Animal   dog = new Dog();

  Cat    cat  =(Cat)dog;

这里的Cat 是继承自Animal 的,但是同样不可以,因为dog 的本身是Dog类型,不是同级的Cat类型。

 三、多态之抽象类 

  A.什么是抽象类

  抽象类就是不能具体的表示一个对象的类,比如动物,它不可能是一个具体的对象,要是想清楚的表示一个对象,那么必须由他的子类猫或者狗来表示

  B.怎么描述一个抽象类

          a.前面必须有关键字abstract 来修饰

     b.抽象类中包含抽象方法,抽象方法没有方法体,必须由子类来实现

     c.体现了数据抽象的思想,是实现多态的一种机制

     d.抽象类不能被实例化,它有的只是指向子类对象的引用

     e.从多个类中抽象出一个抽象类,作为子类设计的模板,从而限制了子类设计的随意性

     f.不关心子类的具体实现,只关注子类中必须有什么方法

     g. abstract不能和final同时修饰一个类

                h.abstract 不能与private 、static 、final 等共同修饰同一个方法

抽象类为Telphone,子类是 CellPhone ,SmartPhone,那么代码如下:

public abstract  class Telphone {
    public abstract  void call();
    public abstract   void message();
    public void printf(){
        System.out.println("Hello_abstractClass");
    }
}


public class CellPhone extends Telphone{
  @Override public void call(){ System.out.println("cellPhone电话具有打电话的功能"); } @Override public void message() { System.out.println("CellPhone具有发短信的功能"); } public void inter(){ System.out.println("可以上网"); } } public class SmartPhone extends Telphone{ @Override public void call() { System.out.println("SmartPhone具有打电话的功能"); } @Override public void message() { System.out.println("SmartPhone具有发短信的功能"); } @Override public void printf() { super.printf(); System.out.println("可以输出"); } } public class Initail { public static void main(String[] args){ Telphone tel1=new CellPhone(); Telphone tel2=new SmartPhone(); CellPhone tel3=new CellPhone(); CellPhone tel4=(CellPhone) tel1; tel4.inter(); tel3.inter(); tel1.call(); tel1.message(); tel1.printf(); tel2.call(); tel2.message(); tel2.printf(); } }

  从这段代码中可以看出来抽象类的引用指向了子类的对象,并且可以调用子类实现的方法,但是有一点就是当子类中的独有方法时,父类的引用是不可以调用的,惟有子类的引用可以调用。如上图的inter()方法。

四、多态之接口

  A.什么是接口

  接口是一组规范,并不关心类的具体的数据与实现,只是规定了类该实现哪些方法,是用来约束类的,

   B.么描述接口

  a.接口是一个特殊的类,其中可以是公共的常量和公共的抽象方法组成

    b.使用interface关键字定义接口

       c.是public abstract(可以有,没有显示出现的话,会被隐式添加上) 

    d.接口是可以多继承的,它可以继承多个父接口

  如:

  修饰符  (abstract)   接口名 [ extends   父接口1 ,父接口2,....]

  {

      0~n个常量

      0~n个抽象方法的定义  

  }

  e.接口中是常量,修饰符是public static final ,如果没有写,系统会隐式的添加

  f.定义方法时修饰是public abstract,如果没有添加,那么系统会自动添加

  g.一个类可以实现一个或多个接口,多个接口之间使用,分隔开来,使用implements实现接口

  h.在继承一个类的同时也可以实现接口,但是继承的类必须在实现接口之前

  如:

  修饰符  class   类名  extends  父类    implements   接口1, 接口2....

public abstract interface IplayGame{
    public static final int IGrade=1;//可以在接口中定义常量

    public void playGame();

}



public class CellPhone extends Telphone implements IplayGame{
    public void call(){
        System.out.println("cellPhone电话具有打电话的功能");
    }

    @Override
    public void message() {
        System.out.println("CellPhone具有发短信的功能");
    }

    
    public void inter(){
        System.out.println("可以上网");
    }

    @Override
    public void playGame() {
        System.out.println("CellPhone 不能打游戏");
    }
}

public class initail {
         public static void main(String[] args){
((CellPhone) tel1).playGame();
        System.out.println(CellPhone.IGrade);
    }
}

 在这段代码中,有一个接口IplayGame,CellPhone 实现了IplayGame这个接口,然后用了CellPhone 的引用调用这个接口中的常量和方法。

  I.使用匿名内部类实现接口

IplayGame  ip1= new IplayGame() {
            @Override
            public void playGame() {
                System.out.println("使用匿名内部类实现接口");
            }
        };
        ip1.playGame();
        
        
        
        new IplayGame() {
            @Override
            public void playGame() {
                System.out.println("使用匿名内部类实现了接口2");        
            }
        }.playGame();

     在匿名内部类中可以直接new 一个接口的引用,后来可以用接口的引用直接调用我们的接口内的方法。个人觉得这个就像是在接口中实现了抽象方法,然后利用接口的引用调用了被实现的方法,这个接口就相当于一个类(如有不对的,还请多多指教!!!).

多态的就总结到这儿,下面简单的说一下接口和抽象类的区别:

1.关键字不同 

2.接口中不能有被实现了的方法,抽象类中可以有

3.接口可以实现多继承,抽象类只能单继承

4.接口中只能是成员常量,抽象类中可以成员变量

5.继承抽象类的子类必须和抽象类本身有继承关系,则存在 is a的关系,但是实现接口不一定,只要能够实现接口中定义的方法即可

 

每天总结一点点,坚持