在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

我们给匿名内部类传递参数的时候,若该形参在内部类中需要被使用,那么该形参必须要为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 final_java提高篇(十)-----详解匿名内部类 ,形参为什么要用final相关推荐

  1. 【转】java提高篇(十)-----详解匿名内部类

    原文网址:http://www.cnblogs.com/chenssy/p/3390871.html 在java提高篇-----详解内部类中对匿名内部类做了一个简单的介绍,但是内部类还存在很多其他细节 ...

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

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

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

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

  4. c#加入json库引用_C#如何通过匿名类直接使用访问JSON数据详解

    实验目的 在C#和Rest/Restful以及其它的Web服务交互过程中,大量使用到JSON传递数据,如何快捷的转化C#对象到JSON和转化JSON到C#对象,成为开发过程中频繁使用的内容.传统的方式 ...

  5. java入门提高篇:Day1 抽象类

    java入门提高篇:Day1 抽象类 基础部分内容差不多讲解完了,今天开始进入Java提高篇部分,这部分内容会比之前的内容复杂很多,希望大家做好心理准备,看不懂的部分可以多看两遍,仍不理解的部分那一定 ...

  6. JAVA中的类和对象之this的详解

    系列文章目录 第一章 JAVA中的类和对象之this的详解 目录 前言 一.为什么要有this引用 二.this的三种用法 1.this.成员变量 2.this.成员方法 3.this()调用其它的构 ...

  7. java新建一个女朋友_详解java创建一个女朋友类(对象啥的new一个就是)==建造者模式,一键重写...

    创建一个女朋友,她有很多的属性,比如:性别,年龄,身高,体重,类型等等,虽然每个女朋友都有这些属性,但是每个人找女朋友的要求都是不一样的,有的人喜欢男的,有的人喜欢女的,有的喜欢胖的,不同的人可以根据 ...

  8. Java多线程之线程池详解

    Java多线程之线程池详解 目录: 线程池使用及优势 线程池3个常用方式 线程池7大参数深入介绍 线程池底层工作原理 1. 线程池使用及优势 线程池做的工作主要是控制运行的线程的数量,处理过程中将任务 ...

  9. JVM调优系列--Java命令选项(参数)--大全/详解/常用

    原文网址:JVM调优系列--Java命令选项(参数)--大全/详解/常用_IT利刃出鞘的博客-CSDN博客 简介 说明        本文介绍Java的java命令用法,包括:常用用法.选项大全. J ...

最新文章

  1. 全变量进气系统伺服马_三种伺服电动缸系统的特点
  2. 电脑电视兼容成科技行业新课题
  3. Android中的意图匹配--IntentFilter的作用
  4. MySQL 8.0 可以操作 JSON 了,牛!
  5. MFC CEdit 自动换行功能
  6. 使用V-chart时配置踩过的一些坑
  7. Excel VBA 处理图形图表详解
  8. JEECG开源团队招募新成员 2014年
  9. Yarn报错:error Couldn‘t publish package: “https://registry。。。 Are you logged in as the correct user?“
  10. python小工具自动审单录凭证_跟着老板工作了二十年,最近来了个新员工然后我被开除了...
  11. 单点登录SSO的实现原理与方案详解
  12. tick_init 函数
  13. balser相机IP设置
  14. 踏破铁鞋,Vmware 8完美安装Mac Lion狮子系统,CPU不支持虚拟化,键盘无响经验共享
  15. 射频遥控:固定码与学习码的区别
  16. 青春,让人想念,却再也闻不到了
  17. 教你新浪爱拍相册图片批量下载
  18. vuex原理解析并实现一个简单的vuex
  19. matlab画简单长方形,matlab在图像中画长方形(框)
  20. 2023北京联合大学计算机考研信息汇总

热门文章

  1. extern 声明函数和定义函数
  2. 299. Bulls and Cows
  3. apache点NET环境
  4. HIVE之 DDL 数据定义 DML数据操作
  5. hibernate.cfg.xml ,hibernate.properties 关系
  6. HDU 2844 Coins 多重背包
  7. 理解SQL SERVER中的分区表(转)
  8. Linux 动态库剖析
  9. Windows用户模式下的线程同步
  10. CYYMysql 源码解读 2