java基础之:匿名内部类

简介: 在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客。在这篇博客中你可以 了解到匿名内部类的使用、匿名内部类要注意的事项、如何初始化匿名内部类、匿名内部类使用的形参为何要为final。

  在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节问题,所以就衍生出这篇博客。在这篇博客中你可以 了解到匿名内部类的使用、匿名内部类要注意的事项、如何初始化匿名内部类、匿名内部类使用的形参为何要为final。


       一、使用匿名内部类内部类

       匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。创建格式如下:

 

  1. new 父类构造器(参数列表)|实现接口()    
  2.     {    
  3.      //匿名内部类的类体部分    
  4.     }  

       在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。

 

  1. public abstract class Bird {  
  2.     private String name;  
  3.   
  4.     public String getName() {  
  5.         return name;  
  6.     }  
  7.   
  8.     public void setName(String name) {  
  9.         this.name = name;  
  10.     }  
  11.       
  12.     public abstract int fly();  
  13. }  
  14.   
  15. public class Test {  
  16.       
  17.     public void test(Bird bird){  
  18.         System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米");  
  19.     }  
  20.       
  21.     public static void main(String[] args) {  
  22.         Test test = new Test();  
  23.         test.test(new Bird() {  
  24.               
  25.             public int fly() {  
  26.                 return 10000;  
  27.             }  
  28.               
  29.             public String getName() {  
  30.                 return "大雁";  
  31.             }  
  32.         });  
  33.     }  
  34. }  
  35. ------------------  
  36. Output:  
  37. 大雁能够飞 10000米  

       在Test类中,test()方法接受一个Bird类型的参数,同时我们知道一个抽象类是没有办法直接new的,我们必须要先有实现类才能new出来它的实现类实例。所以在mian方法中直接使用匿名内部类来创建一个Bird实例。

       由于匿名内部类不能是抽象类,所以它必须要实现它的抽象父类或者接口里面所有的抽象方法。

       对于这段匿名内部类代码其实是可以拆分为如下形式:

 

  1. public class WildGoose extends Bird{  
  2.     public int fly() {  
  3.         return 10000;  
  4.     }  
  5.       
  6.     public String getName() {  
  7.         return "大雁";  
  8.     }  
  9. }  
  10.   
  11. WildGoose wildGoose = new WildGoose();  
  12. test.test(wildGoose);  

       在这里系统会创建一个继承自Bird类的匿名类的对象,该对象转型为对Bird类型的引用。

       对 于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不 能够被重复使用。对于上面的实例,如果我们需要对test()方法里面内部类进行多次使用,建议重新定义类,而不是使用匿名内部类。


       二、注意事项

       在使用匿名内部类的过程中,我们需要注意如下几点:

      1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。

      2、匿名内部类中是不能定义构造函数的。

      3、匿名内部类中不能存在任何的静态成员变量和静态方法。

      4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。

      5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。


       三、使用的形参为何要为final

       参考文件:http://android.blog.51cto.com/268543/384844

       我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使用,那么该形参必须要为final。也就是说:当所在的方法的形参需要被内部类里面使用时,该形参必须为final。

      为什么必须要为final呢?

      首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部类并不是同一class文件,仅仅只保留对外部类的引用。当外部类传入的参数需要被内部类调用时,从java程序的角度来看是直接被调用:

 

  1. public class OuterClass {  
  2.     public void display(final String name,String age){  
  3.         class InnerClass{  
  4.             void display(){  
  5.                 System.out.println(name);  
  6.             }  
  7.         }  
  8.     }  
  9. }  

      从上面代码中看好像name参数应该是被内部类直接调用?其实不然,在java编译之后实际的操作如下:

 

  1. public class OuterClass$InnerClass {  
  2.     public InnerClass(String name,String age){  
  3.         this.InnerClass$name = name;  
  4.         this.InnerClass$age = age;  
  5.     }  
  6.       
  7.       
  8.     public void display(){  
  9.         System.out.println(this.InnerClass$name + "----" + this.InnerClass$age );  
  10.     }  
  11. }  

       所以从上面代码来看,内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上时自己的属性而不是外部方法传递进来的参数。

       直 到这里还没有解释为什么是final?在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也 就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部 类该变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。

      简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。

      故如果定义了一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器会要求该参数引用是final的。


       四、匿名内部类初始化

       我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。

 

  1. public class OutClass {  
  2.     public InnerClass getInnerClass(final int age,final String name){  
  3.         return new InnerClass() {  
  4.             int age_ ;  
  5.             String name_;  
  6.             //构造代码块完成初始化工作  
  7.             {  
  8.                 if(0 < age && age < 200){  
  9.                     age_ = age;  
  10.                     name_ = name;  
  11.                 }  
  12.             }  
  13.             public String getName() {  
  14.                 return name_;  
  15.             }  
  16.               
  17.             public int getAge() {  
  18.                 return age_;  
  19.             }  
  20.         };  
  21.     }  
  22.       
  23.     public static void main(String[] args) {  
  24.         OutClass out = new OutClass();  
  25.           
  26.         InnerClass inner_1 = out.getInnerClass(201, "chenssy");  
  27.         System.out.println(inner_1.getName());  
  28.           
  29.         InnerClass inner_2 = out.getInnerClass(23, "chenssy");  
  30.         System.out.println(inner_2.getName());  
  31.     }  
  32. }  


巩固基础,提高技术,不惧困难,攀登高峰!!!!!!

相关文章
|
5月前
|
Java 程序员
深入理解Java匿名内部类的语法和使用场景
深入理解Java匿名内部类的语法和使用场景
|
2月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
88 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
6月前
|
Java
【Java基础】输入输出流(IO流)
Java基础、输入输出流、IO流、流的概念、输入输出流的类层次结构图、使用 InputStream 和 OutputStream流类、使用 Reader 和 Writer 流类
192 2
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
Java 编译器
【Java】内部类
【Java】内部类
23 0
|
4月前
|
Java
【Java基础面试二】、个Java文件里可以有多个类吗(不含内部类)?
这篇文章讨论了Java文件中类的定义规则,指出一个Java文件可以包含多个类(不包含内部类),但其中最多只能有一个public类,且如果有public类,它的名称必须与文件名一致。
|
4月前
|
算法 Java
12 Java常用类(一)(内部类+object类+包装类)
12 Java常用类(一)(内部类+object类+包装类)
41 5
|
5月前
|
Java
Java进阶之内部类
【7月更文挑战第13天】Java内部类增进代码组织与封装,允许直接访问外部类成员,包括私有成员。主要有四种类型:成员、静态、局部和匿名内部类。匿名内部类常用于一次性实现接口或扩展类。内部类可隐藏实现细节,减少命名冲突,并在特定上下文中定义辅助类。示例展示了静态和非静态内部类如何在Shape类中封装Circle和Rectangle。使用内部类能提升代码可读性,但可能增加复杂性。
43 6
|
4月前
|
Java
【Java】内部类、枚举、泛型
【Java】内部类、枚举、泛型
|
6月前
|
Java
一篇文章讲明白Java中内部类详解—匿名内部类
一篇文章讲明白Java中内部类详解—匿名内部类
99 2