原文网址:http://www.cnblogs.com/chenssy/p/3390871.html

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

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

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

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

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

public abstract class Bird {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public abstract int fly();
}public class Test {public void test(Bird bird){System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米");}public static void main(String[] args) {Test test = new Test();test.test(new Bird() {public int fly() {return 10000;}public String getName() {return "大雁";}});}
}
------------------
Output:
大雁能够飞 10000米

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

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

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

public class WildGoose extends Bird{public int fly() {return 10000;}public String getName() {return "大雁";}
}WildGoose wildGoose = new WildGoose();
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程序的角度来看是直接被调用:

public class OuterClass {public void display(final String name,String age){class InnerClass{void display(){System.out.println(name);}}}
}

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

public class OuterClass$InnerClass {public InnerClass(String name,String age){this.InnerClass$name = name;this.InnerClass$age = age;}public void display(){System.out.println(this.InnerClass$name + "----" + this.InnerClass$age );}
}

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

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

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

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

四、匿名内部类初始化

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

public class OutClass {public InnerClass getInnerClass(final int age,final String name){return new InnerClass() {int age_ ;String name_;//构造代码块完成初始化工作{if(0 < age && age < 200){age_ = age;name_ = name;}}public String getName() {return name_;}public int getAge() {return age_;}};}public static void main(String[] args) {OutClass out = new OutClass();InnerClass inner_1 = out.getInnerClass(201, "chenssy");System.out.println(inner_1.getName());InnerClass inner_2 = out.getInnerClass(23, "chenssy");System.out.println(inner_2.getName());}
}

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

PS:如果你觉得文章对你有所帮助,别忘了推荐或者分享,因为有你的支持,才是我续写下篇的动力和源泉!

作者: chenssy 
出处: http://www.cnblogs.com/chenssy/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

【转】java提高篇(十)-----详解匿名内部类相关推荐

  1. 匿名类 java final_java提高篇(十)-----详解匿名内部类 ,形参为什么要用final

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

  2. java提高篇之详解内部类

    转载自 java提高篇之详解内部类 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面看是非常容易理解的,无 ...

  3. java提高篇(八)----详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  4. java提高篇(十六)-----异常(一)

    Java的基本理念是"结构不佳的代码不能运行"!!!!! 大成若缺,其用不弊. 大盈若冲,其用不穷. 在这个世界不可能存在完美的东西,不管完美的思维有多么缜密,细心,我们都不可能考 ...

  5. JAVA学习篇--Servlet详解

    Servlet由来 做过BS项目的人都知道,浏览器能够根据HTML静态标记语言来显示各式各样的网页.但是如果我们需要在网页上完成一些业务逻辑:比如登陆验证.或者说网页显示的内容在服务器的数据库中.如果 ...

  6. java提高篇(十二)-----代码块

    在编程过程中我们可能会遇到如下这种形式的程序: public class Test {{ } } 这种形式的程序段我们将其称之为代码块,所谓代码块就是用大括号({})将多行代码封装在一起,形成一个独立 ...

  7. Java基础篇------抽象类详解

  8. Java定时任务调度工具详解之Timer篇

    Java定时任务调度工具详解之Timer篇 https://segmentfault.com/a/1190000009542398

  9. python java混合编程_详解java调用python的几种用法(看这篇就够了)

    java调用python的几种用法如下: 在java类中直接执行python语句 在java类中直接调用本地python脚本 使用Runtime.getRuntime()执行python脚本文件(推荐 ...

最新文章

  1. 阿里大佬分享API网关在微服务架构中的应用
  2. python3 赋值与内存空间
  3. php编译工具 知乎,关于知乎回答问题编辑框用Ctrl+V 粘贴图片是如何实现的详解...
  4. 一些安全相关的HTTP响应头
  5. Qt中多线程间的互斥
  6. String*Buffer*Builder理解
  7. Activity生命周期(二)
  8. shell脚本之从1加到100之和的思路
  9. python能自学成功吗-为什么那么多自学Python的后来都放弃了,总结起来就这些原因...
  10. R语言的cpp扩展支持Rcpp模块介绍
  11. java 求两点的角度_计算两点之间的角度 – java
  12. 人人商城小程序服务器根目录,人人商城前端小程序如何配置 人人商城搭建教程...
  13. RiruEdxposed学习研究(四)Magisk(面具)源码下载编译详细实战教程
  14. 计算机excel试题各科学员,计算机Excel练习题一及答案.doc
  15. 电脑编程入门自学java_电脑编程入门自学Java指南
  16. [Mysql] GROUP BY分组
  17. odoo开发笔记 -- 官方模块一览表
  18. GAMES101-现代计算机图形学入门-闫令琪 - lecture15 光线追踪3 - 辐射度量学、渲染方程(Ray Tracing 3) - 课后笔记
  19. python 安装pytorch apex 报错:“ERROR: Command errored out with exit status 1: /home/litt/anaconda3/envs/”
  20. 关于语义分析的简单总结

热门文章

  1. 解决Python2.7的UnicodeEncodeError: ‘ascii’ codec can’t encode异常错误
  2. TensorFlow MNIST最佳实践
  3. Java 学习(1) ---JDK安装和配置环境变量
  4. Git bash 终止git log 命令
  5. (转) GPG入门教程
  6. 【.NET程序性能分析】使用VS自带的工具分析.NET程序的性能
  7. 【你知道HHTP各种状态代表什么意思吗?】
  8. 网站基于文本搜索的实现
  9. 使用R语言进行中文分词
  10. celery 停止任务_celery异步任务框架