黑马程序员——Java基础---继承、抽象、接口(二)

来源:互联网 发布:adobe acrobat for mac 编辑:程序博客网 时间:2024/06/05 10:01

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


一、多态

1.多态概述 

   定义:某一类事物的多种存在形态。
    

    例:动物中猫,狗。
    猫这个对象对应的类型是猫类型:猫 x = new 猫();
    同时猫也是动物中的一种,也可以把猫称为动物:动物 y = new 猫();
    动物是猫和狗具体事物中抽取出来的父类型。父类型引用指向了子类对象。

    多态性简单说就是一个对象对应着不同类型。

    体现:
    父类或者接口的引用指向或者接收自己的子类对象。

    作用:
    多态的存在提高了程序的扩展性和后期可维护性。

    
    前提:
    1. 需要存在继承或者实现关系。
    2. 需要有覆盖操作。

    
    好处:
    提高了代码的扩展性,前期定义的代码可以使用后期的内容。
    弊端:
    前期定义的内容不能使用(调用)后期子类的特有内容。

示例:
/** * 需求:演示多态 * 思路:程序中注释部分 * @author jinlong * */package com.blog.part2.继承;//定义抽象类Animalabstract class Animal{    abstract void eat();}//定义抽象类的子类Dogclass Dog extends Animal{//重写了抽象类eat方法    void eat()    {         System.out.println("啃骨头");    }    //他还有自己的特有方法    void lookHome(){         System.out.println("看家");    }}//类似上边Dog类,再定义一个Cat类class Cat extends Animal{    void eat()    {         System.out.println("吃鱼");    }    //同样有自己的特有方法    void catchMouse()    {         System.out.println("抓老鼠");    }}//与cat、Dog类似class Pig extends Animal{    void eat()    {         System.out.println("饲料");    }    void gongdi()    {         System.out.println("拱地");    }}class DuoTaiDemo{    public static void main(String[] args)    {        //自动类型提升,猫对象提升到了动物类型。但是特有功能无法访问,作用就是限制对特有功能的访问。        //专业讲:向上转型,将子类型隐藏。就不能使用子类的特有方法了。        Animal a = new Cat();        //但是还可以使用覆盖自父类的方法eat        a.eat();        //a.catchMouse();//报错,        //如果还想用具体动物猫的特有功能。        //你可以将该对象进行向下转型。        Cat c = (Cat)a; //向下转型的目的是为了能够使用子类中的特有方法。        c.eat();        c.catchMouse();        //注意:对于转型,自始至终都是子类对象在做类型的变化。        //Animal a = new Dog();        //Cat c = (Cat)a;//但是类型不能随意转换,否则可能会报出ClassCastException的异常        /*         为了避免这种错误,可以使用instanceof判断        if(a instanceof Cat)           {              Cat c = (Cat )a;            c.catchMouse();           }          */   }   //定义方法调用eat,传入参数类型为这个抽象类    public static void method(Animal a)    {         a.eat();    }}
运行结果:


2.多态时成员的特点 

1.成员变量

               编译时:参考引用型变量所属的类中是否有调用的成员变量。有,编译通过,没有,编译失败。
      运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
      简单说:编译和运行都参考等号的左边。
       
package com.blog.part2.继承;class Fu{    int num = 3;}class Zi extends Fu{    int num = 4;    }class DuoTaiDemo1{    public static void main(String[] args)    {        //编译和运行都是看等号左边变量所属类是否有成员变量         Zi f1 = new Zi();         System.out.println(f1.num);                  Fu f2 = new Zi();         System.out.println(f2.num);    }}
运行结果:

2.成员函数(非静态)

       编译时:参考引用型变量所属的类中是否有调用的函数。有,编译通过。没有,编译失败。
       运行时:参考的是对象所属的类中是否有调用的函数。
       简单说:编译看左边,运行看右边。


示例:
package com.blog.part2.继承;class Fu{    void show()    {    System.out.println("Fu show");    }}class Zi extends Fu{    void show()    {    System.out.println("Zi show");    }    }class DuoTaiDemo1{    public static void main(String[] args)    {        //编译看左边,运行看右边         Zi f1 = new Zi();         f1.show();                  Fu f2 = new Zi();        f2.show();    }}
运行结果:

3.成员函数(非静态)

       编译时:参考的是对象所属的类中是否有调用的函数。
   运行时:参考的是对象所属的类中是否有调用的函数。
   简单说:编译和运行看左边。


package com.blog.part2.继承;class Fu{    static void show()    {    System.out.println("Fu show");    }}class Zi extends Fu{    static void show()    {    System.out.println("Zi show");    }    }class DuoTaiDemo1{    public static void main(String[] args)    {        //静态方法无序实例化就可以直接用类名调用,这里为了和上边的示例对比    //编译运行都看左边         Zi f1 = new Zi();         f1.show();  //其实就是Zi.show()               Fu f2 = new Zi();        f2.show();//其实就是Fu.show()            }}
运行结果:


二、内部类

1.概述

    定义:
    将一个类定义在另一个类的里面,里面那个类就称为内部类(内置类,嵌套类)。

    访问特点:
    内部类可以直接访问外部类中的成员,包括私有成员。
    而外部类要访问内部类中的成员必须要建立内部类的对象。

    内部类设计:在设计事物时,发现这个事物中还有事物,并且这个事物还在访问被描述事物的内容,这是时就定义内部类。

2.内部类的位置

1.内部类在成员位置

      内部类定义在成员位置上可以被private、static成员修饰符修饰。
   被static修饰的内部类只能访问外部类中的静态成员,这就出现了访问局限

   访问格式:当内部类定义在外部类的成员位置上,且非私有,可以在外部其他类中直接建立内部类对象。格式如下:

          Outer.Inner in=new Outer().new Inner();

示例:
/** * 需求:内部类展示 * @author jinlong * */package com.blog.part2.继承;class Outer{//外部类静态成员    private static int num = 3;    private int sum=0;    //内部类    static class Inner    {    //静态内部类的非静态方法          void show()          {                  System.out.println("static show run..." + num);                  //静态内部类只能访问外部类的静态成员,访问非静态会报错                 // System.out.println("show run..." + sum);          }      //静态内部类的静态方法          static void show1()          {          System.out.println("show run..." + num);          }    }}class InnerClassDemo{    public static void main(String[] args)    {        //访问静态成员不需要创建对象    Outer.Inner.show1();          //如果内部类是静态的,相当于一个外部类         Outer.Inner in = new Outer.Inner();         in.show();                   }}
  注意:当内部类中定义了静态成员,该类也必须是静态的。当外部类的静态方法访问内部类时,该类也必须是静态的。
 

         

2.内部类在局部

    内部类定义在局部位置上,也可以直接访问外部类中的成员。
    同时可以访问所在局部中的局部变量,但必须是被final修饰的。
/** * 需求:内部类定义在局部 * @author jinlong * */package com.blog.part2.继承;class Outer{    int num = 3;    //如果要被inner类中函数使用,这里参数必须被final修饰    void method(final int y)    {          final int x = 9;          //局部定义的内部类,在method方法中          class Inner          {                void show()                {                     System.out.println("show..." + x + "," + y);                }          }          //创建内部类对象。         Inner in = new Inner();         in.show();    }}class InnerClassDemo{    public static void main(String[] args)    {          new Outer().method(4);    }}

3.匿名内部类

1.概述

    定义:
    就是内部类的简化写法。

    前提:
    内部类可以继承或实现一个外部类或者接口。

    格式:
    new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}


    简单理解:
    就是建立一个带内容的外部类或者接口的子类匿名对象。


    什么时候使用匿名内部类呢?
    通常使用方法是接口类型参数,并且该接口中的方法不超过三个,可以将匿名内部类作为参数传递。

    好处:
    增强阅读性。


2.一些常见示例

示例一:

/** * 需求:同过匿名类使用抽象类中的方法。 * @author jinlong * */package com.blog.part2.继承;//定义一个抽象类abstract class Demo{    abstract void show();}class Outer{    int num = 4;    void method()    {    //          new Demo(){//匿名内部类,在局部                void show()                {                //重写了抽象类的函数                     System.out.println("show......" + num);               }          }.show();    }}class InnerClassDemo{    public static void main(String[] args)    {    //一次性调用,可以用匿名类          new Outer().method();    }}

实例二:

package com.blog.part2.继承;/** * 需求:同过匿名类使用接口中的方法 * @author jinlong * *///定义一个接口interface Inter{    void show1();    void show2();}class Outer{    public void method()    {    //主以这里其实是new Inter(){...};结构最后的分号不要丢    //最后用inter类型的变量指向他         Inter in = new Inter()         {           //覆盖接口的方法                public void show1()                {                       System.out.println("...show1...." );                }                public void show2()                {                       System.out.println("...show2...." );                }         };         //调用复写的方法。         in.show1();         in.show2();    }}class InnerClassDemo{    public static void main(String[] args)    {          new Outer().method();    }}

示例三:

/** *    通常的使用场景之一:   当函数参数是接口类型时,而且接口中的方法不超过三个。   可以用匿名内部类作为实际参数进行传递。      思考:实际上类似于前边多态的例子,只不过这里不创建抽象类的真正意义上的子类             而通过new 抽象类()                                {                                     重写抽象类方法func1...func2...                                };             这种形式,作为一种临时性的使用。                     * @author jinlong * */package com.blog.part2.继承;interface Inter{    void show1();    void show2();}class InnerClassDemo{   public static void main(String[] args)   {   //注意这里的结构,为show(Inter in),但是参数的传入值有点胖   //结构为 new Inter(){..show1.....show2...}          show(new Inter()          {                public void show1()                {                     System.out.println("...show1..." );                }                public void show2(){                     System.out.println("...show2..." );                }         });    }       public static void show(Inter in)    {         in.show1();         in.show2();    }}




0 0