匿名内部类有没有构造方法(匿名内部类有构造器吗)

匿名内部类有没有构造方法(匿名内部类有构造器吗)

应用场景

由于匿名内部类不利于代码的重用,因此,一般在确定此内部类只会使用一次时,才会使用匿名内部类。

形式

public class OutterClass { public Runnable task() { return new Runnable() { @Override public void run() { System.out.println(“匿名内部类…”); } }; } }

这种实现方式是不是很眼熟呢?

// 初始化线程实例 Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println(“匿名内部类…”); } });

我们为线程创建一个Runnable子类实例的方式,就是一种匿名内部类的写法。我们通过这种没有名字的类,实现了将实现类(下称子类)实例创建与子类定义结合在一起的优雅格式,这也就是所谓的“使用类的定义直接创建实例”。

上面的代码是实现了Runnable接口,并重写了其中的run()方法,当然我们可以自己定义一个类(非接口)然后通过这种匿名内部类的方式来隐式的继承,并重写基类中的方法。

不论是继承父类,还是实现接口,实际上拿到的是父类或接口的引用。这个父类引用实际指向的是一个由匿名内部类定义的类的实例。因此,这个被继承的父类(或接口)必须是事先存在的。否则,编译器会提示你创建这个类。

使用规则

经过查阅资料和实操得出的匿名内部类的几条规则:

规则一:匿名内部类中的方法都是通过父类引用访问的,所以,如果定义了一个在父类中没有的方法,那么这个方法是不能被这个父类引用调用到的。(可以仅仅作为匿名内部类中方法之间的代码共享)。

规则二:匿名内部类既可以继承父类,也可以实现接口,但是不能两者兼备。而且如果实现接口也只能实现一个接口。

规则三:匿名内部类中不可能有构造器。但可通过实例初始化块 来达到构造器的效果,但是也不能重载实例初始化方法(即仅有一个这样的“构造器”)。

规则四:在匿名内部类中如果希望使用一个其外部定义的对象,那么编译器会要求其参数引用是final的。

关于第四条规则,这里牵涉了一个重要的且比较复杂的问题。

使用案例:

/** 定义接口*/ public interface MyInterface { void doSomething(); }

public class TryUsingAnonymousClass { // 外部类成员方法 public MyInterface useMyInterface() { final int number = 201855;// jdk1.8后可以省略final final Object obj = new Object();// jdk1.8后可以省略final MyInterface myInterface = new MyInterface() { // 匿名内部类 @Override public void doSomething() { System.out.println(“匿名内部类中使用基本数据类型:” + number); System.out.println(“匿名内部类中使用引用数据类型:” + obj); } }; return myInterface; } public static void main(String args) { TryUsingAnonymousClass tc = new TryUsingAnonymousClass(); MyInterface inter = tc.useMyInterface(); inter.doSomething(); } }

输出:

匿名内部类中使用基本数据类型:201855 匿名内部类中使用引用数据类型:java.lang.Object@15db9742

我们通过匿名内部类的方式实现了接口MyInterface,并使用了外部类的成员方法useMyInterface() 中定义的两个局部变量:

int number = 201855; Object obj = new Object();

(在jdk1.8之后,新增了effectively final功能,开发者可以不必显式地使用final关键字来修饰局部内部类或匿名内部类中用到的局部变量,由系统默认添加。)

因此我们在匿名内部类中用到的局部变量必须为常量(对于基本类型,其值恒定不变;对于引用类型,其引用,即指向的地址恒定不变)。

如果强行改值,则会报错(这是在1.8程序上未使用final定义number时的尝试,系统果然默认此值为final的):

匿名内部类有没有构造方法(匿名内部类有构造器吗)

不得不引出的局部变量与匿名内部类实例生命周期问题

我们知道成员方法中的局部变量是在运行期进行定义和初始化的,而局部内部类(包括匿名内部类)虽然是在方法中定义的,但是它却依然会在编译期实现从java文件到class文件的转化,即编译成class文件。

编译期在前,运行期在后。而我们却要在编译期使用运行期定义的变量!

怎么办?我们脑海中浮现了两个在编译期便能取得常量的相关关键字:static final 但显然,static无法定义局部变量。

那final能为我们的程序带来什么?

翻阅《Java编程思想》中对final关键字的剖析(第四版,140页):

一个永不改变的编译时常量。

《深入理解Java虚拟机:JVM高级特性与最佳实践》中(第二版,168页)对于Class文件常量池也做出了相关解释:

常量池(博主注:此常量池为class文件常量池,非运行时常量池,两者最大的区别是后者具有动态性)

中主要存放两大类常量:字面量和符号引用。字面量比较接近于Java语言层的常量概念,如文本字符串、声明为final的常量值等。

int型局部变量number和Object类型obj在方法useMyInterface()执行完毕之后即结束了生命周期,但是在下面通过调用inter对象的doSomething()方法依然可以有效的输出这两个值,说明这两个常量并没有受到外部类方法执行完毕而导致局部变量生命周期结束的问题,实际上number和obj已经存在于匿名内部类对应的class文件中的常量池中。

虽然final修饰的常量解决了在编译期拿到运行期的变量的问题,但是final带来的副作用是,这个值无法改变。

对于需要改变局部变量值的情况,我们可以通过在匿名内部类中使用赋值的方式(学名:引用拷贝 =.0)来“接管”局部变量的值,然后我们就可以随意更改这个值了。

综上,就是最近对匿名内部类的研究和讨论。结合了final关键字的用法和class文件常量池来多角度讨论匿名内部类的final常量问题。

—专注IT职场经验、IT技术分享的灵魂写手—

—每天带你领略IT的魅力—

—期待与您陪伴!—

本文【匿名内部类有没有构造方法(匿名内部类有构造器吗)】由作者: Web服务 提供,本站不拥有所有权,只提供储存服务,如有侵权,联系删除!
本文链接:https://www.cuoshuo.com/blog/4560.html

(0)
上一篇 2023-03-15 08:46:55
下一篇 2023-03-16 08:04:38

相关推荐

  • php开源系统排行(php开发环境)

    近两年来,关于PHP编程语言的讨论声越来越多,很多人唱衰PHP,也有人热衷于讨论“PHP还能火多久”之类的话题,但在小编看来,任何技术的存在,都是需要去考虑业务场景的。据W3Techs近日发布的网站使用语言统计报告显示,在已知服务器端编程语言的所有网站中,有77.6%的网站都在使用PHP语言,有很多中小微型企业还是十分依赖PHP,PHP的应用场景依旧热闹非凡…

    2023-03-16
    100
  • 微服务开发16g内存够用吗

    随着微服务的普及,许多企业踏上微服务之旅。 微服务化后,应用数量可能高一个数量级。 一般企业,以前三五个应用能支撑业务,微服务化之后应用数量可能多达几十个。 每个微服务往往独立部署,内存的消耗自然也高居不下,以前两台8核16G机器指不定就能跑起来,现两台16核64G还不一定够用,同时由于多套环境的存在加上容器编排工具(如K8s)所需的资源,硬件资源的投入自然…

    2023-03-14
    000
  • java正则表达式匹配数字_java正则表达式返回匹配字符

    字符串是不可变的,也就是说当字符串的内容发生改变的时候,会创建一个新的String对象;但是如果内容没有发生改变的时候,String类的方法会返回原字符串对象的引用。 而正则表达式往往都和字符串相关,而且很多String对象中的方法都可以使用正则表达式来作为参数,比如:replace();方法,split();方法等,这些方法因为支持正则表达式,便可以以少量…

    2023-03-09
    600
  • html特殊字符空格的代码_html文本开头空两格

    一、什么是HTML HTML简介 HTML是用来描述网页的一种语言,它是一种超文本标记语言,由一套标记标签组成,在制作网页时,HTML使用标记标签来描述网页。 发展史 HTML:Hyper Text Markup Language超文本标记语言 超文本标记语言—在1993年6月互联网工程工作小组工作案发布(并非标准) HTML2.0—1995年11月作为RF…

    2023-03-11
    400
  • java工程师面试一般会问哪些问题,java开发工程师面试题

    前言 2023 跳槽不迷茫,大家可以先收藏再看,后续跳槽都能用上的! Java程序员绝大部分工作的时间都是增删改查,很多人觉得这项工作没什么技术含量,任何一件事情都要站在不同的角度去考虑,对于大部分的java程序员来讲开始前几年就是在为了达成增删改查而努力,大部分的程序员具备这种能力之后就开始相对安逸的状态了,增删改查的功能如果对于简单的工程代码来讲就是比较…

    2023-03-17
    000
  • java常量和变量的区别_java变量赋值给常量

    学习常量和变量之前,让我们先来了解一下常量和变量的含义: 常量:简单理解就是不能改变的量; 变量:可以改变的量。 是不是觉得太简单了,当然没有这么简单,下面我们通过实例先来定义一下变量和常量。大家能看出区别吗? public class ClAndBl { int a = 10; //成员变量(全局变量) static int b = 10; //静态成员变…

    2023-03-08
    800
  • 软件设计师教程第五版_软件设计师教程最新版

    本人坐标上海,两年前从制造业国企转行到工业互联网,离开国企后上海户口是真心难拿,准备走居转户的道路。之前在培训机构咨询过软件设计师和其他科目,说如果是为了拿户口不建议软件设计师,因为偏难通过率偏低。不过想到自己本来就是转行缺少专业知识,加上户口需要中级职称,一举两得,就决定报考软件设计师。 前面介绍了背景,在上海的人都知道户口对于一个准备在上海长期发展的人意…

    2023-03-13
    700
  • 如何设置gridview的风格样式_vs中gridview控件的使用

    阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: GridView 主要用法 GridView 使用案例 GridView 跟ListView 很类似,Listview 主要以列表形式显示数据,GridView 则是以网格形式显示数据,掌握ListV…

    2023-03-17
    300
  • css选择器的类型和作用

    你学会了基本的id,class类选择器和descendant后代选择器,然后就觉得完事了吗?如果这样,你就会错过许多灵活运用CSS的机会。虽然本文提到的许多选择器都属于CSS3,并且只能在现代的浏览器中使用,但学会这些是大有好处的。 什么是CSS选择器呢? 每一条css样式定义由两部分组成,形式如下:选择器{样式}[/code]在{}之前的部分就是“选择器”…

    2023-03-12
    400
  • .net邮件发送

    1、安装Nuget包MailKit,引用命名空间。 using MailKit.Net.Smtp; using MimeKit;注意:引用MailKit对应最新版本 2、定义收发地址和标题 MimeMessage message = new MimeMessage(); MailboxAddress from = new MailboxAddress(&#0…

    2023-03-14
    600

发表回复

登录后才能评论
返回顶部
错说博客上线啦!