黑馬程序員——面向對象 筆記第六篇

多態、內部類

-----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();

    }

}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章