黑马程序员——面向对象<四> 笔记第六篇

多态、内部类

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


11 多态

多态: 一个对象具有多种形态。(父类的引用类型变量指向了子类的对象)

多态前提: 必须要存在继承或者实现的关系。

 

多态要注意的细节:

1. 多态情况下,子父类存在同名的成员变量时,都是访问父类的成员变量。

2. 多态情况下,子父类存在着同名的非静态函数时,默认访问的是子类的成员函数。

3. 多态情况下,子父类存在着同名的静态函数时,默认访问的是父类的成员函数。

4. 多态情况下,不能访问或者调用子类特有的成员,如果真的需要访问那么需要进行强制类型转换。

 

总结:多态情况下,子父类存在同名的成员时,默认都是访问父类的成员,

           只有子父类存在非静态函数是才是访问子类的成员函数。

 

 

编译看左边,运行不一定看右边。

 

编译看左边: java编译器在编译的时候,会检查引用类型所属的类是否具备指定的成员,如果不具备那么编译报错。

 

运行:多态情况下,子父类存在同名的成员时,默认都是访问父类的成员,

         只有子父类存在非静态函数是才是访问子类的成员函数。

 

多态的应用场景:

         1.多态应用于形参类型的时候,方法可以接收更多类型的参数。

         2.多态用于返回值类型的时候,可以返回更多类型的参数。

多态的好处:提高了程序的拓展性。

 

总结

1:当父类和子类具有相同的非静态成员变量,那么在多态下访问的是父类的成员变量

2:当父类和子类具有相同的静态成员变量,那么在多态下访问的是父类的静态成员变量

    所以:父类和子类有相同的成员变量,多态下访问的是父类的成员变量。

3:当父类和子类具有相同的非静态方法(就是子类重写父类方法),多态下访问的是子类的成员方法。

4:当父类和子类具有相同的静态方法(就是子类重写父类静态方法),多态下访问的是父类的静态方法。

2:多态体现

       1:父类引用变量指向了子类的对象

       2:父类引用也可以接受自己的子类对象

3:多态前提

    1:类与类之间有关系,继承或者实现

4:多态弊端

    1:提高扩展性,但是只能使用父类引用指向父类成员。

5:多态特点

    非静态

1:编译时期,参考引用型变量所属的类是否有调用的方法,如果有编译通过。没有编译失败

    2:运行时期,参考对象所属类中是否有调用的方法。

    3:总之成员函数在多态调用时,编译看左边,运行看右边。

    在多态中,成员变量的特点,无论编译和运行参考左边(引用型变量所属的类)。

    在多态中,静态成员函数特点,无论编译和运行都参考左边

 

例子:

/*

 * 需求:定义一个函数可以接收任意类型的图形对象。

 */

 

//图形类

abstract  class MyShape{

   

    public abstract void getArea();

 

    public abstract void getLength();

}

 

 

//矩形

class Rect extends MyShape{

    int width ;

    int height ;

   

    public Rect(intwidth , intheight){

       this.width =width;

       this.height =height;

    }

 

    public void getArea(){

       System.out.println("矩形面积是:"+width*height);

    }

 

    public  void getLength(){

       System.out.println("矩形周长是:"+ 2*(width+height));

    }

}

//圆形

class Circle extends MyShape{

    public static final double PI = 3.14;

    int r;

    public Circle(intr){

       this.r =r;

    }

   

    public void getArea(){

       System.out.println("圆形面积是:"+PI*r*r);

    }

    public  void getLength(){

       System.out.println("圆形周长是:"+ 2*PI*r);

    }

}

 

public class Duotai

{

    public static void main(String[] args)

    {

       /*

       Circle c = new Circle(4);

       Rect r = new Rect(3,4);

       print(r);

       */

       MyShape c = getShape(1);

       c.getArea();

       c.getLength();

    }

 

    //需求:定义一个函数可以接收任意类型的图形对象。

    public static void print(MyShape m){  // MyShape m  =  new Rect(3,4);

       m.getLength();

       m.getArea();

    }

 

    //需求:编写一个函数可以返回任意类型的图形对象。

    public static MyShape getShape(inti){

       if (i==0){

           return new Circle(4);

       }else{

           return new Rect(4,5);

       }

    }

}

 

多态与数据类型转换的例子

/*

     引用类型数据转换:

    小数据类型数据---------->大数据类型   自动类型转换。

    大数据类型数据----------->小数据类型   强制类型转换。

 */

 

//动物

class Animal {

    String name;

    String color;

    static int x = 10;

    //构造函数

    public Animal(Stringname,String color){

       this.name =name;

       this.color =color;

    }

    public  void eat(){

       System.out.println("动物在吃饭...");

    }

}

 

//

class Dog extends Animal {

    static int x = 20;

    public Dog(Stringname,String color){

       super(name,color);

    }

    public  void eat(){

       System.out.println("狗在吃狗粮...");

    }

    //狗特有的方法咬人

    public void bite(){

       System.out.println(name+"狠狠的咬人!!");

    }

}

//

class Fish extends Animal{

    public Fish(Stringname,String color){

       super(name,color);

    }

    public void eat(){

        System.out.println("鱼在吃草...");

    }

    //鱼特有的方法

    public void swing(){

       System.out.println("鱼在游泳...");

    }

}

 

public  class Duotai

{

    public static void main(String[] args)

    {

       /*System.out.println("Hello World!");

       Fish f = new Fish("草鱼","墨绿色");

       Dog d = new Dog("哈巴狗","白色");

       print(d);

 

       Animal a =getAnimal(0);

       a.swing();

       Animal a = new Fish("草鱼","墨绿色");

       //在多态的情况下,就是不能访问到子类特有的成员,如果需要访问子类特有的成员,那么需要做强制类型转换。

       Fish f = (Fish)a; //把动物又强制转换成鱼

       f.swing();

       */

       Fish f = new Fish("草鱼","墨绿色");

       Dog d = new Dog("哈巴狗","白色");

       print2(f);

    }

    //需求3:定义一个函数可以接收任意类型的动物对象,在方法内部调用动物对象特有的方法。

    public static void print2(Animal a){

       if(ainstanceof Fish){

           Fish f  = (Fish)a;  //把动物强制转换成鱼

           f.swing();

       }else if(a instanceof Dog){

            Dog d = (Dog)a;

           d.bite();

       }

    }

    //需求1:定义一个函数可以接收任意类型的动物对象。

    public static void print(Animal a){

       a.eat();

    }

    //需求2编写一个函数可以返回任意类型的动物对象。

    public static Animal getAnimal(inti){

       if(i==0){

           return new Fish("草鱼","墨绿色");

       }else{

           return new Dog("哈巴狗","白色");

       }

    }

}

 

 

12 内部类

成员内部类:定义一个类在类的内部,方法的外部,称作为成员内部类。

 

成员内部类访问方式:                        

         方式1:在外部提供一个方法创建内部类 的对象进行访问。

         方式2: 在其他类直接创建内部类对象进行访问。

创建对象的格式: 

外部类.内部类  变量名= new 外部类().new 内部类();

注意:如果是静态的成员内部类的在其他类创建对象:外部类.内部类  变量名= new 外部类.内部类(); 

Outer.Inner   inner = new Outer.Inner();  //静态内部类的访问方式

 

内部类的好处:内部类的好处就是可以直接访问外部类的成员。

 

内部类的写法

class Outer{

         class Inner

         {

                   public void show(){

                            System.out.println("内部类的show方法");

                   }

         }

         public void print(){

                   new Inner().show();

         }

}

 

12.1成员内部类要注意的细节:

1. 成员内部类可以直接访问外部类的成员。

2. 如果外部类与内部类存在同名的成员变量时,在内部类中默认是访问内部类的成员,可以通过"外部类.this.成员变量名" 指定访问外部类 的成员变量。

3. 如果内部类使用了private修饰,那么访问该内部类的时候就只能在外部类提供一个方法进行访问了。不能在其他类直接创建了。

4. 如果成员内部类出现了静态的成员,那么该成员内部类也需要使用static修饰。

         疑问:如果成员内部类出现了静态的成员,那么该成员内部类也需要使用static修饰?

    原因:假如没有使用static修饰,那访问非静态成员时,得创建对象再调用new Outer().Inner.x,与Java规范有矛盾,使用成员内部类也需要使用static修饰。

java规范:静态的数据不需要依赖于对象进行访问

 

细节的说明范例

//外部类

class Outer{  

   

    //成员变量.

     int x = 100;

 

    //成员内部类

    static class Inner{  

 

       static int x = 999;

      

       //成员变量

       int i = 10;

 

       //成员函数

       public void print(){

           System.out.println("这个是内部类的print方法.. x =  "+x);

       }

    }

   

    //在外部提供一个方法创建内部类的对象进行访问。

    public void visitedInner(){

       //创建一个内部的对象

       Inner in = new Inner();

       System.out.println("i = "+in.i);

    }

 

}

 

 

//其他类

class Way

{

 

    public static void main(String[] args)

    {

      

       /*

       //创建一个外部类的对象

       Outer outer = new Outer();

       outer.visitedInner();

   

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

       System.out.println("i = "+inner.i);

       inner.print();

 

       Outer.Inner   inner = new Outer.Inner();  //静态内部类的访问方式

       inner.print();

       */

    }

}

 

 

12.2局部内部类:

局部类要注意的细节:

         局部内部类访问局部变量的时候,局部变量是需要使用final修饰的。

//外部类

class Outer{

    public void test(){

       //局部变量

       final  int y = 100; /*  y的生命周期:test方法执行完毕之后马上从内存消失。

       局部内部类访问局部变量的时候,局部变量是需要使用final修饰,为什么?

       */

       //局部内部类

       class Inner{

           //成员变量

              intx = 10;  

           //成员函数

           public void print(){

              System.out.println("这个是局部内部类的print方法..."+y);

              /*

                  y变量当方法执行完毕的时候就已经从内存中消失了,

                  这时候test方法执行完毕的时候Inner对象还没有消失,y消失了,

                  但是Innner对象的方法还在访问着y变量,这时候给人的感觉就是y还没有消失,

                  y变量的生命周期被延长了。

 

                  解决方案:如果局部内部类访问一个局部变量的时候,那么就让局部内部类访问的是

                  一个变量复制品。源变量可以正常消失。

              */

           }

       }

       //创建局部内部类对象

       Inner inner = new  Inner();// Inner对象生命周期:反正Inner的对象当test执行完毕之后还不会马上消失。

                                // Inner对象的生命周期是比y要长的。

       inner.print();

    }

}

 

class Way

{

    public static void main(String[] args)

    {

       Outer outer = new Outer();

       outer.test();

    }

}

12.3 匿名内部类

使用前提:必须要存在着继承或者实现的关系

好处:简化书写

 

继承关系下的匿名内部类

//动物类

abstract class Animal{

    public abstract void run();

    public  abstract void sleep();

}

 

 

class Outer{

    public void print(){

       /*

       //需求:定义一个类继承Animal,然后创建该类的对象调用runsleep方法。

       class Bird extends Animal{

   

           public void run(){

              System.out.println("鸟飞得更高!!");

           }

           public void sleep(){

              System.out.println("鸟在睡觉!!");

           }

       }

 

       //使用该内部类创建对象。

       Bird b = new Bird();

       b.run();

       b.sleep();

       */

   

       //匿名内部类只是没有类名,其他一个类该有的成员,匿名内部类都是具备的。

      

       //匿名内部类实现

       Animal b = new Animal(){ //匿名内部类与Animal的关系是继承。  多态

           //匿名内部的成员

           public void run(){

              System.out.println("鸟飞得更高!!");

           }

           public void sleep(){

              System.out.println("鸟在睡觉!!");

           }

           //子类特有的方法...

           public void eat(){

              System.out.println("鸟在吃!!");

              //return this;

           }

       };

      

       //b.eat();

       b.run();

       b.sleep();

    }

}

 

public class Demo

{

    public static void main(String[] args)

    {

       Outer outernew Outer();

       outer.print();

    }

}

 

 

接口关系下的匿名内部类

 

interface A{

    public void add();

}

 

class Outer{

    public void print(){

       //实现关系下的匿名内部类

       new A(){  //这个匿名内部类与A接口的关系是实现关系。

           //匿名内部类的成员

           public void add(){

              System.out.println("这个是添加的方法..!");

           }

       }.add();

    }

}

 

class Demo3

{

    public static void main(String[] args)

    {

       Outer outer = new Outer();

       outer.print();

    }

}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值