Java 8 改进的匿名内部类

适用范围:

匿名内部类适合于方便程序实现接口,即匿名内部类相当于接口的实现类。

创建原理:

创建匿名内部类在实现接口的时候会立即创建一个没有名字类的实例用来实现某一接口,这个类立即创建立即消失,匿名内部类不能重复使用
(匿名内部类中有一个隐式的无参构造器)

定义匿名内部类的格式如下:

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

关于匿名内部类还有如下规则:

  1. 从上面定义可以看出,匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。(相当于匿名内部类继承了一个父类或者实现了一个接口是接口的实现类)
  2. 匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。因此不允许将匿名内部类定义成抽象类(抽象类不能实例化)
  3. 匿名内部类不能定义构造器。由于匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义初始化块,可以通过实例初始化块来完成构造器需要完成的事情。

最常见的创建匿名内部类的方式是需要创建某个接口类型的对象,如下程序所示:

//定义一个产品的接口
interface Product{double getPrice();String getName();}
public class AnonymousTest {//定义一个方法实现“买”这种行为;public void test (Product p){System.out.println("购买了一个"+p.getName()+",花掉了"+p.getPrice());};public static void main(String[] args) {AnonymousTest at=new AnonymousTest();//调用test()方法时,需要传递一个参数//此处通过匿名内部类实现at.test(new Product() {@Overridepublic double getPrice() {return 57.8;}@Overridepublic String getName() {return "APG显卡";}});}}

上面程序中的AnonymousTest定义了一个test( ) 方法,该方法需要一个 Product对象作为参数,但Product只是一个接口,无法直接创建对象,因此此处考虑创建一个Product接口实现类的对象传入该方法(即匿名内部类)

如果这个Prodect接口实现类需要重复使用,则应该将该实现类定义成一个独立类;如果这个Product接口实现类只需使用一次,则可采用上面程序中的方式,定义一个匿名内部类。
//如果需要重复使用Product接口,那么将实现类定义为独立类;

class implementsClass implements Product{@Overridepublic double getPrice() {return 0;}@Overridepublic String getName() {return null;}
}

定义匿名内部类无须 class 关键字,而是在定义匿名内部类时直接生成该匿名内部类的对象。由于匿名内部类不能是抽象类(抽象类不能实例化),所以匿名内部类必须实现它的抽象父类或者接口里包含的所有抽象方法,

下面是对于上面代码的另外一种实现方式(接口需要重复使用,则将实现类定义为一个独立类):

class implementsClass implements Product{@Overridepublic double getPrice() {return 57.8;}@Overridepublic String getName() {return "AGP显卡";}at.text(new implementsClass());

上面两段代码功能完全一样,只不过采用匿名内部类的写法更加简洁。

当通过实现接口来创建匿名内部类时,匿名内部类也不能显式创建构造器,因此**匿名内部类只有一个隐式的无参数构造器,**故 new 接口后的括号里不能穿入参数。但如果通过继承父类来创建匿名内部类时,匿名内部类讲拥有和父类相似的构造器,此处的相似是指拥有相同的形成列表。(当匿名内部类用来实现抽象类的时候可以将抽象类看作是匿名类内部类的父类,即匿名内部类会继承抽象类的所有的方法,也可以使用抽象类中的构造器)

看下面的程序:

//定义一个抽象类
abstract class Device {private String name;public abstract double getPrice();public Device(){};public Device(String name){this.name=name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
public class AnonymousInner{public void test(Device d){System.out.println("购买了一个"+d.getName()+",花掉了"+d.getPrice());}public static void main(String[] args) {AnonymousInner ai=new AnonymousInner();//调用有参数的构造器来实现匿名内部类ai.test(new Device("电子示波器") {@Overridepublic double getPrice() {return 67.8;}});//调用无参数的的构造器创建匿名内部类Device d=new Device() {//初始化代码块{System.out.println("匿名内部类初始化代码块……");}@Overridepublic double getPrice() {return 56.3;}//重写父类的实例方法public String getName(){return "键盘";}};ai.test(d);}}

上面程序创建了一个抽象父类Devite 类,这个抽象父类里面包含两个构造器:一个无参数的,一个有参数的。当创建以 Devite为父类的匿名内部类时,既可以传入参数,代表调用父类带参数的构造器;也可以不传入参数,代表调用父类无参数的构造器。当创建匿名内部类时,必须实现接口或抽象父类里的所有抽象方法。如果有需要,也可以重写父类中的普通方法。如上面程序中,匿名内部类重写了抽象父类Devite类的 getName ( ) 方法,其中 getName ( ) 方法并不是抽象方法。

在 Java 8 之前,Java 要求被局部内部类、匿名内部类访问的局部变量必须使用 final 修饰,从 Java 8 开始这个限制被取消了,Java 8 更加智能:如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了 final 修饰。

interface Student
{void getAge();}public class InnerDemo {public static void main(String [] args){int age=10;    //1⃣️Student student=new Student() {@Overridepublic void getAge() {//在 Java 8 以前下面语句将提示错误,age 必须使用 final 修饰//从 java 8 开始,匿名内部类、局部内部类允许访问非 final 的局部变量System.out.println(age);}};student.getAge();}
}

Java 8 将这种功能称为“ effectivity final ” ,它的意思是对于被匿名内部类访问的局部变量,可以用 final 修饰,也可以不用 final 修饰,但必须按照油final 修饰的方式来用——也就是一次赋值后,以后不能重新赋值。如上面程序如果在1⃣️代码后添加如下代码:age=20;将会导致编译错误。(即java8以后被匿名内部类访问的局部变量相当于自动加上了final修饰符,不可以对该局部变量就行二次赋值)

解析java匿名内部类相关推荐

  1. 深入解析Java AtomicInteger 原子类型

    深入解析Java AtomicInteger原子类型 在进行并发编程的时候我们需要确保程序在被多个线程并发访问时可以得到正确的结果,也就是实现线程安全.线程安全的定义如下: 当多个线程访问某个类时,不 ...

  2. java jni 数据类型_【Android JNI】Native层解析Java复杂数据类型HashMap

    前提 Java HashMap 是基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.HashMap是存放引用类型数据的容器,只能存放引用数据类型,不能存 ...

  3. 转 : 深入解析Java锁机制

    深入解析Java锁机制 https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw%3D%3D&mid=2247485524&idx=1&s ...

  4. java 获取spring对象数组_解析Java中如何获取Spring中配置的bean

    解析Java中如何获取Spring中配置的bean Java中如何获取Spring中配置的bean?下面是由百分网小编为大家整理的解析Java中如何获取Spring中配置的bean,喜欢的可以收藏一下 ...

  5. 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁

    上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和主要的方法,显示了如何 ...

  6. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现,这篇拿Semaphore信号量做例子看看AQS实际是如何使用的. Semaphore表示了一种可以同时有多个线程进入临界区的同步器,它维护了一个状态表示可用的票据, ...

  7. 聊聊高并发(二十二)解析java.util.concurrent各个组件(四) 深入理解AQS(二)

    上一篇介绍了AQS的基本设计思路以及两个内部类Node和ConditionObject的实现 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一) 这篇 ...

  8. 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一)

    AQS是AbstractQueuedSynchronizer的缩写,AQS是Java并包里大部分同步器的基础构件,利用AQS可以很方便的创建锁和同步器.它封装了一个状态,提供了一系列的获取和释放操作, ...

  9. java 日期 解析_Java日期解析(Java DATE Parsing)

    Java日期解析(Java DATE Parsing) 我有一个java.util.Date的愚蠢问题. 我有这一行代码,但我不明白为什么这个日期是用这种格式无法解析的. public class T ...

最新文章

  1. 本地xshell损坏了着急拷贝服务器上的大文件怎么办?有办法lrzsz来帮忙
  2. 修复思维导图mindmanager移动文件位置后打开崩溃
  3. HttpRequest 与HttpWebRequest 有什么区别
  4. python引用类 魔法方法_Python 学习笔记 -- 类的魔法方法
  5. C++ Primer 5th笔记(chap 19 特殊工具与技术)局部类
  6. 白夜:一文看懂AI项目流程及边缘设备开发
  7. spring中@param和mybatis中@param使用区别
  8. 论文浅尝 | 利用知识-意识阅读器改进的不完整知识图谱问答方法
  9. vmware 搭建k8s无法ping通子节点_一波四折 —— 记一次K8S集群应用故障排查
  10. STM32F103系列实战之通用同步异步收发器(USART)
  11. linux下centeros7 关于mysql的下载与安装过程
  12. 利用SiteMapPath控件做论坛导航
  13. 2021年校招软件测试工程师经典面试题,月薪15K你需要掌握哪些知识点?
  14. Create-React-App创建antd-mobile开发环境
  15. 微信小程序(翻译小助手)项目实战
  16. 当程序员具备了抽象思维
  17. 华为当个pl怎么样_华为8PL∪S提示灯 | 手游网游页游攻略大全
  18. 华三设备常用调试命令
  19. 内连接外连接全连接(简单实例)
  20. HTML5期末大作业:电商购物网站设计——电商购物网站设计(55页) 电商网页设计制作 简单静态HTML网页作品 购物网页作业成品 学生商城网站模板

热门文章

  1. 在HP安腾服务器上安装SuSE Linux Enterprise Server(SLES)11SP1手记
  2. Codeforces Round #554 (Div. 2) C. Neko does Maths (简单推导)
  3. 回文串 --- 动态dp UVA 11584
  4. zabbix 安装使用
  5. Zipline Development Guidelines
  6. php之判断点在多边形内的api
  7. maven项目下tomcat直接启动不了(LifecycleException)。报错如下截图
  8. vmware虚拟机环境里用linux和xp系统测试防火墙的nat转换
  9. JS操作Excel读取和写入(模板操作)
  10. Discuz!论坛,如何查看全站最新帖子列表?