天天看點

Java中的多态、内部類、匿名内部類

一、多态

        多态可以了解為事物存在的多種展現形态。

例:動物中貓,狗。貓這個對象對應的類型是貓類型,如:貓 x = new貓(); 同時貓也是動物中的一種,也可以把貓稱為動物。動物  y = new貓(); 那麼動物就是貓和狗具體事物中抽取出來的父類型。父類型引用指向了子類對象。

1、多态的展現:父類型的引用或者接口類型的引用指向子類類型的對象。

例如:Person p = new Student();

2、産生多态的前提:

a、類與類之間存在繼承關系,類與接口之間存在實作關系。

b、通常會有覆寫操作。

3、多态的利與弊:

        利:提高了程式的可擴充性和後期可維護性。

        弊:隻能使用父類中的引用通路父類中的成員。也就是說使用了多态,父類型的引用在使用功能時,不能直接調用子類中的特有方法。如:Animal a = new Cat(); 這就是多态的展現,假設子類Cat中有特有的抓老鼠功能,父類型的 a就不能直接調用。這上面的代碼中,可以了解為Cat類型提升為Animal類型,向上轉型。

        如果此時父類的引用想要調用Cat中特有的方法,就需要強制将父類的引用,轉成子類類型,向下轉型。如:Cat  c = (Cat)a;

注意:如果父類可以建立對象,如:Animal a = new Animal(); 此時,就不能向下轉型了,Cat c = (Cat)a; 這樣的代碼就變得不容許,編譯時會報錯。是以千萬不能出現這樣的操作,就是将父類對象轉成子類類型。

        我們能轉換的是父類引用指向了自己的子類對象時,該引用可以被提升,也可以被強制轉換。多态至始至終都是子類對象在做着變化。

多态的代碼示例:

//父類————動物

abstract class Animal

{

      public abstract void eat();

}

//子類————貓

class Cat extends Animal

{

       //複寫父類中的抽象功能

     public void eat()

    {

           System.out.println("吃魚");

    }

     //Cat特有的功能

   public static void catchMouse()

   {

          System.out.println("抓老鼠");

    }

}

class Demo

{

         public static void main(String[] args) 

        {

               Animal a = new Cat();

               a.eat();

              Cat c = (Cat)a;

              c.catchMouse();

        }

}

4、多态的特點

1)多态中非靜态成員函數的特點:

        在編譯時期:參閱引用型變量所屬的類中是否有調用的方法。如果有,編譯通過,如果沒有編譯失敗。

如:在上面的示例中,如果用a.catchMouse();編譯就會報錯。這時隻能通過強轉向下類型轉換後,才可以使用子類的特有功能。

        在運作時期:參閱對象所屬的類中是否有調用的方法。這就是說,如果父類中有一個非抽象的方法,而子類繼承後又将其複寫了,在多态運作時,父類的引用調用這個同名函數時,被運作的将是父類中的方法。

        簡單總結就是:成員函數在多态調用時,編譯看左邊,運作看右邊。

2)多态中成員變量的特點

        無論編譯和運作,都參考左邊(引用變量所屬的類)。如:多态中的父類引用調用成員變量時,如果父類和子類有同名的成員變量,那麼被調用的是父類中的成員變量。

3)多态中靜态成員函數的特點

        無論編譯和運作,都參考左邊。也就是父類引用在調用靜态同名函數時,被調用的是父類中的靜态函數。這是因為,當類一被加載,靜态函數就随類綁定在了記憶體中。此時,不需要建立對象,就可以使用類名直接調用。同時,父類中的靜态成員函數一般是不被複寫的。

5、多态的出現思想上也做着變化:以前是建立對象并指揮對象做事情。有了多态以後,我們可以找到對象的共性類型,直接操作共性類型即可,這樣可以指揮一批對象做事情,即通過操作父類或接口實作。

二、内部類

1,概述:

       如果A類需要直接通路B類中的成員,而B類又需要建立A類的對象。這時,為了友善設計和通路,直接将A類定義在B類中。A類就稱為内部類。内部類可以直接通路外部類中的成員。而外部類想要通路内部類,必須要建立内部類的對象。

編譯時,如果代碼中有内部類,生成的class檔案中會含有這樣的檔案:Test$1.class。編譯器将會把内部類翻譯成用$(美元符号)分隔外部類名和内部類名的正常類檔案。這是内部類的一種編譯現象。

2、内部類的通路規則:

        1、内部類可以直接通路外部類中的成員,包括私有。

              之是以可以直接通路外部類中的成員,是因為内部類中持有了一個外部類的引用,格式:  外部類名.this。

        2、外部類要通路内部類,必須建立内部類對象。

3、通路格式:

       當内部類定義在外部類的成員位置上,而且非私有,可以在外部其他類中直接建立内部類對象。

        格式:

                 外部類名.内部類名  變量名 =外部類對象.内部類對象;

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

當内部類在外部類中的成員位置上時,可以被成員修飾符所修飾。比如:

        private:将内部類在外部類中進行封裝。 

        static:内部類就局部static的特性。但是當内部類被static修飾後,隻能直接通路外部類中的static成員。出現了通路局限。

在外部其他類中,直接通路static内部類的非靜态成員的格式為:

        new 外部類名.内部類名().方法名();

        如:new  Outer.Inner().function();

在外部其他類中,直接通路static内部類的靜态成員格式為:

        外部類名.内部類名.方法名();

        如:Outer.Inner.function();

注意:

        1)當内部類中定義了靜态成員時,該内部類必須是static的。

        2)當外部類中的靜态方法通路内部類時,内部類也必須是static的。

        3)在實際應用中,内部類通常被定義為private,而很少定義為public。

4,為什麼内部類可以直接通路外部類中的成員呢?

那是因為内部中都持有一個外部類的引用。這個引用是 外部類名.this

内部類可以定義在外部類中的成員位置上,也可以定義在外部類中的局部位置上。

當内部類被定義在局部位置上,隻能通路局部中被final修飾的局部變量。

三、匿名内部類:

1、概述:沒有名字的内部類。就是内部類的簡化形式。一般隻用一次就可以用這種形式。匿名内部類其實就是一個匿名子類對象。想要定義匿名内部類:前提是内部類必須繼承一個類或者實作接口。

2、匿名内部類的格式:new 父類名&接口名(){ 定義子類成員或者覆寫父類方法 }.方法。

3、匿名内部類的使用場景:

當函數的參數是接口類型引用時,如果接口中的方法不超過3個。可以通過匿名内部類來完成參數的傳遞。

其實就是在建立匿名内部類時,該類中的封裝的方法不要過多,最好兩個或者兩個以内。

4,代碼示例:

interface Inter

{

       void method();

}

class InnerClassTest 

{

      public static void main(String[] args) 

     {

           show(new Inter()

            {//匿名内部類

                  public void method()

                  {

                       System.out.println("method show run");

                  }

            });

      }

     public static void show(Inter in)

     {

               in.method();

      }

}

5,匿名内部類的一個小練習:

interface Inter

{

      void method();

}

class Test

{

      //通過匿名内部類,補足代碼。

}

class InnerClassDemo 

{

         public static void main(String[] args) 

        {

               Test.function().method();

        }

}

分析:

       Test.function().method();//相當于Inter in=Test.function();

                                            //           in.method();

       Test.function():Test類中有一個靜态的方法function。

        .method():說明調用function這個方法運算後的結果是一個對象。而且是一個Inter類型的對象,因為隻有Inter類型的對象,才可以調用内部類中的method方法。

完整的代碼如下:

interface Inter

{

       void method();

}

class Test

{

         static Inter function()

      {

               return new Inter()

{

                      public void method()

           {

System.out.println("内部類練習");

      }

};

}

}

class InnerClassDemo 

{

public static void main(String[] args) 

{

Test.function().method();

}

}

繼續閱讀