黑马程序员---java匿名内部类

时间:2022-02-06 00:25:20

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------

      简单地说:匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:  

     1.只用到类的一个实例。   

     2.类在定义后马上用到。   

     3.类非常小(SUN推荐是在4行代码以下)。  

     4.给类命名并不会导致你的代码更容易被理解。  

    在使用匿名内部类时,要记住以下几个原则:  

    1.匿名内部类不能有构造方法。   

    2.匿名内部类不能定义任何静态成员、方法和类。  

    3.匿名内部类不能是public,protected,private,static。  

    4.只能创建匿名内部类的一个实例。 

    5.一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。  

    6.因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。     

    下面的例子看起来有点奇怪: 

     //在方法中返回一个匿名内部类

     

     public class Parcel6 {         

              public Contents cont() {                

                       return new Contents() {                     

                              private int i = 11;                        

                              public int value() {                            

                                      return i;                     

                               }               

                        }; // 在这里需要一个分号        

              }           

             public static void main(String[] args) {                

                        Parcel6 p = new Parcel6();                

                        Contents c = p.cont();        

              }

 } 

        cont()方法将下面两个动作合并在一起:返回值的生成,与表示这个返回值的类的定义!进一步说,这个类是匿名的,它没有名字。更糟的是,看起来是你正要创建一个Contents对象: 

       return new Contents() 

       但是,在到达语句结束的分号之前,你却说:“等一等,我想在这里插入一个类的定义”: 

       return new Contents() { 

                private int i = 11; 

                public int value() {

                         return i;

                }

        }; 

       这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象。”通过new 表达式返回的引用被自动向上转型为对Contents的引用。匿名内部类的语法是下面例子的简略形式:

        class MyContents implements Contents { 

                 private int i = 11; 

                 public int value() {

                       return i;

                  }     

          }  return new MyContents(); 

         在这个匿名内部类中,使用了缺省的构造器来生成Contents。下面的代码展示的是,如果你的基类需要一个有参数的构造器,应该怎么办:

         public class Parcel7 { 

                 public Wrapping wrap(int x) { 

                          // Base constructor call: 

                          return new Wrapping(x) { // Pass constructor argument. 

                                   public int value() { 

                                           return super.value() * 47;             

                                   } 

                           }; // Semicolon required     

                 } 

                 public static void main(String[] args) { 

                         Parcel7 p = new Parcel7();

                          Wrapping w = p.wrap(10);     

                 } 

         } 

      只需简单地传递合适的参数给基类的构造器即可,这里是将x 传进new  Wrapping(x)。在匿名内部类末尾的分号,并不是用来标记此内部类结束(C++中是那样)。实际上,它标记的是表达式的结束,只不过这个表达式正巧包含了内部类罢了。因此,这与别的地方使用的分号是一致的。     如果在匿名类中定义成员变量,你同样能够对其执行初始化操作: 

        public class Parcel8 { 

             // Argument must be final to use inside

             // anonymous inner class: 

             public Destination dest(final String dest) { 

                    return new Destination() { 

                             private String label = dest; 

                             public String readLabel() { return label;

                             }

                    };    

               }

              public static void main(String[] args) { 

                      Parcel8 p = new Parcel8(); 

                      Destination d = p.dest("Tanzania");     

              }

        }  

       如果你有一个匿名内部类,它要使用一个在它的外部定义的对象,编译器会要求其参数引用是final 型的,就像dest()中的参数。如果你忘记了,会得到一个编译期错误信息。如果只是简单地给一个成员变量赋值,那么此例中的方法就可以了。但是,如果你想做一些类似构造器的行为,该怎么办呢?在匿名类中不可能有已命名的构造器(因为它根本没名字!),但通过实例初始化,你就能够达到为匿名内部类“制作”一个构造器的效果。像这样做:

       abstract class Base { 

               public Base(int i) { 

                       System.out.println("Base constructor, i = " + i);     

               } 

               public abstract void f();

       }   

       public class AnonymousConstructor { 

                 public static Base getBase(int i) { 

                          return new Base(i) {             

                                  { 

                                         System.out.println("Inside instance initializer");             

                                  } 

                                 public void f() { 

                                          System.out.println("In anonymous f()");             

                                  } 

                          };    

               } 

              public static void main(String[] args) { 

                         Base base = getBase(47);

                         base.f();     

              }

        }  

        在此例中,不要求变量i 一定是final 的。因为i 被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。下例是带实例初始化的“parcel”形式。注意dest()的参数必须是final,因为它们是在匿名类内被使用的。

        public class Parcel9 { 

                  public Destinationdest(final String dest, final float price) { 

                             return new Destination() { 

                                         private int cost; 

                                          // Instance initialization for each object:             

                                          { 

                                                 cost = Math.round(price);

                                                 if(cost > 100) 

                                                         System.out.println("Over budget!");             

                                           }   

                                           private String label = dest; 

                                           public String readLabel() {

                                                   return label;

                                           }

                            };     

               } 

               public static void main(String[] args) { 

                         Parcel9 p = new Parcel9(); 

                         Destination d = p.dest("Tanzania", 101.395F);     

                }

       } 

        在实例初始化的部分,你可以看到有一段代码,那原本是不能作为成员变量初始化的一部分而执行的(就是if 语句)。所以对于匿名类而言,实例初始化的实际效果就是构造器。当然它受到了限制:你不能重载实例初始化,所以你只能有一个构造器。

 

 

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------