java基础之:匿名内部类
在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());
- }
- }

巩固基础,提高技术,不惧困难,攀登高峰!!!!!!
java基础之:匿名内部类的更多相关文章
- java 基础(匿名内部类)
匿名内部类 特点:不对外公开,进行实现功能,继承类,继承抽象类,实现某个接口的匿名内部类,实现相应的方法 特别注意:匿名内部类,匿名指的是 ,new 关键字右边的那个对象--如继承,或是接口 { ...
- java基础04 匿名内部类
内部类 (1)把类定义在另一个类的内部,该类就被称为内部类. 举例:把类B定义在类A中,类B就被称为内部类. (2)内部类的访问规则 A:可以直接访问外部类的成员,包括私有 B:外部类要想访问内部类成 ...
- java基础之匿名内部类
内部类: 概述: 类里边还有一个类, 里边那个类叫内部类, 外边那个类叫外部类. 分类: 成员内部类: 定义在成员位置的内部类. 局部内部类: 定义在局部位置的内部类. 格式: new 类名或者接口名 ...
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
JAVA基础再回首(二十五)--Lock锁的使用.死锁问题.多线程生产者和消费者.线程池.匿名内部类使用多线程.定时器.面试题 版权声明:转载必须注明本文转自程序猿杜鹏程的博客:http://blog ...
- [Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)
如若转载请注明出处: http://www.cnblogs.com/wang-meng/p/5898837.html 谢谢.上一篇发了一个找工作的面经, 找工作不宜, 希望这一篇的内容能够帮助到大 ...
- 【JAVA面试题系列一】面试题总汇--JAVA基础部分
JAVA基础 基础部分的顺序: 基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法 线程的语法,集合的语法,io 的语法,虚拟机方面的语法 每天几道,持续更新!! 1.一个". ...
- java基础知识(五)java类
类是java的核心和本质,是java语言的基础. 一.java中的类 1.类class 一个类可以包含局部变量.实例变量.类变量(静态变量) 一个类至少有一个构造方法,如果没有,系统会默认给出一个无参 ...
- Java基础进阶整理
Java学习笔记整理 本文档是我个人整理的,首先是想通过完成本文档更加扎实自己的基础加强对java语言的理解,然后就是想给入了门的同志们做下贡献. 当然,本文档主要是对java语言基础(当然还有很多基 ...
- 四、Android学习第四天——JAVA基础回顾(转)
(转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的 ...
- java基础要点
Java语言是现在比较常用的编程语言,因为Java语言可以编写桌用程序,也可以编写web程序,还能编写嵌入式程序.这是由于相比脚本语言,Java 的运行速度要快.而对于底层语言,Java与平台无关,可 ...
随机推荐
- JS小问题总结
1. 超链接中href=#与href=javascript:void(0) 的区别 #包含了一个位置信息.默认的锚是#top 也就是网页的上端:而javascript:void(0) 仅仅表示一 ...
- 修改Azure Website 移动服务 默认时区
Azure Website 默认时区为国际标准时间,对中国用户来说不太方便友好,如何设置成北京时间呢? 打开Azure Website的“配置”页,找到“应用设置”节点. 在应用设置中添加设置项,密钥 ...
- HTML--4格式布局
一.position:fixed 锁定位置(相对于浏览器的位置),例如有些网站的右下角的弹出窗口. 示例: 二.position:absolute 1.外层没有position:absolute(或r ...
- PAT 10-1 在字符串中查找指定字符
百度了一下另外两位同学的做法,都是先判断是否匹配,然后再用一个for()循环输出,我当然也是先判断,然后,就直接puts(),还是巧妙一点,题设要求及代码实现如下 /* Name: Copyright ...
- Jquery中的prop()方法 全选或全不选
注意: prop()在高版本才会有效, 低版本用attr(); $(function(){ // 元素checkbox var aChecked = $('.checkGoods'); // 全选 v ...
- comet
comet 1.简介: 基于 HTTP长连接的“服务器推”技术,是一种新的 Web 应用架构,基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求.C ...
- LeetCode 笔记系列 19 Scramble String [合理使用递归]
题目: Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty subs ...
- iOS 开发之推力动画效果
步骤: 1.使用single view application 创建新的项目 2.在.h文件中需要遵守两个协议<UICollisionBehaviorDelegate,UIGestureReco ...
- 如何调用super
因此,决定是否调用 super,基于您打算如何重新实施方法: 如果打算补充超类实现的行为,请调用 super. 如果打算替换超类实现的行为,就不要调用 super. 如果您要补充超类行为,另一个需要重 ...
- C# INotifyPropertyChanged
INotifyPropertyChanged 向客户端发出某一属性值已更改的通知. namespace System.ComponentModel{ // Summary: // Notifies c ...