匿名内部类(内部类) - Java

匿名内部类

    • 1、理解
    • 2、语法
    • 3、使用
      • (1)基于接口的内部类
      • (2)基于类的内部类
      • (3)基于抽象类的匿名内部类
    • 4、细节&注意事项
    • 5、最佳应用场景
      • (1)当作实参直接传递,简洁高效。
      • (2)练习

1、理解

(1)类:本质是类。
(2)内部类:定义在一个类的内部。
(3)匿名:该类没有名字。其实有名字,但是是系统起的。
(4)同时还是一个对象。

说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名。

2、语法

	new 类或者接口(参数列表) {类体}

3、使用

(1)基于接口的内部类

为什么需要《匿名内部类》?
① 需求:在Outer04 类的method方法中,想使用 IA 接口,并创建对象
② 传统方式:写一个类,实现该接口,并在method方法中 创建对象

interface IA {public void cry();
}
//外部类
class Outer04 {private int n1 = 10;public void method() {IA tiger = new Tiger();//接口的多态tiger.cry();IA dog = new Dog();//接口的多态dog.cry();}
}class Tiger implements IA{@Overridepublic void cry() {System.out.println("老虎叫唤···");}
}class Dog implements IA{@Overridepublic void cry() {System.out.println("小狗汪汪叫···");}
}
public class AnonymouslnnerClass {public static void main(String[] args) {Outer04 outer04 = new Outer04();outer04.method();}
}

在这里插入图片描述
③ 引出问题:这个tiger和dog对象可能只使用一次,后面不使用,浪费。
④ 可以使用匿名内部类来简化开发。

匿名内部类优化后:

class Outer04 {private int n1 = 10; public void method() {IA tiger_ = new IA() {@Overridepublic void cry() {System.out.println("老虎喊叫···");}};tiger_.cry();}
}

【分析】:
tiger 的编译类型? —— IA
tiger 的运行类型? —— 匿名内部类

底层:
XXXX = Outer04$1 底层(不是程序员)分配类名

class XXXX implements IA {@Overridepublic void cry() {System.out.println("老虎喊叫···");}
}

在这里插入图片描述
new
底层创建好类之后,立马new了一个。jdk 底层在创建匿名内部类 Outer04$1后,立即马上就创建了 Outer04$1实例,并且把地址返回给 tiger。


匿名内部类使用一次,就不能再使用。
匿名内部类不是tiger,tiger还是可以用的。
就是匿名内部类在方法区的模板不在了,但是通过模板创建的对象还在。
类加载在方法区;类 new 出来的对象在堆里面。虽然类用一次没了,但是new的对象还在。

(2)基于类的内部类

class Outer04_ {private int n1 = 10;public void method() {Father father = new Father("jack") {};}
}
//类
class Father {public Father(String name) {}public void test() {}
}

【分析】:
father 的编译类型? —— Father
father 的运行类型? —— 匿名内部类 Outer04_$1
(①这里为了与上一个Outer04类做区分,重新创建了一个Outer04_类,名字上多了一个下划线 ②如果还是在Outer04类内部,那么此时的运行类型是Outer04$2,是按照顺序分配的。)

【底层】创建匿名内部类:
class Outer04_$1 extends Father {
//里面什么都没有写,因为Father类的两个方法都有实现(实现=有大括号)
}
这里已经不是Father类了,是新的类Outer04_$1

匿名内部类重写方法
重写之后的底层:

class Outer04_$1 extends Father {@Overridepublic void test() {System.out.println("匿名内部类重写了Fathter中的test方法");}
}
class Outer04_ {private int n1 = 10;public void method() {Father father = new Father("jack") {@Overridepublic void test() {System.out.println("匿名内部类重写了Fathter中的test方法");}};System.out.println("father的运行类型=" + father.getClass());}
}

Father father = new Father(“jack”) {};中的new
同时也直接返回了匿名内部类Outer04_$1 的对象。

Father father = new Father(“jack”) {};中的参数列表“jack”
"jack"会传递给Father的构造器。

(3)基于抽象类的匿名内部类

上述的Father不是抽象类,如果是抽象类就需要实现。

class Outer04_ {public void method2() {//基于抽象类的匿名内部类Animal ani = new Animal() {@Overridepublic void eat() {System.out.println("吃吃吃");}};ani.eat();}
}
//抽象类
abstract class Animal {abstract public void eat();
}

4、细节&注意事项

  1. 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点。
    因此可以调用匿名内部类方法有下面两种:AnonymousInnerDetails.java【见下文 案例a】
  2. 可以直接访问外部类的所有成员,包含私有的。
  3. 不能添加访问修饰符,因为它的地位就是一个局部变量。
  4. 作用域:仅仅在定义它的方法或代码块中。
  5. 匿名内部类—>访问—>外部类成员 [访问方式:直接访问]
  6. 外部其他类—>不能访问—>匿名内部类(因为匿名内部类地位是一个局部变量)
  7. 如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

【案例a】

  • 方法一
public class AnonymousInnerDetails {public static void main(String[] args) {Outer05 outer05 = new Outer05();outer05.f1();}
}
class Outer05 {private int n1 = 99;public void f1() {Person p = new Person() {@Overridepublic void hi() {System.out.println("匿名内部类重写hi~");}};//p的编译类型 Person//p的运行类型 Outer05$1p.hi();//动态绑定}
}class Person {public void hi() {System.out.println("Person-hi()~");}
}
  • 方法二 直接调用,匿名内部类本身也是返回对象
class Outer05 {public void f2() {new Person() {@Overridepublic void hi() {System.out.println("匿名内部类重写hi~哈哈哈哈");}}.hi();}
}

在这里插入图片描述

  • 带参数调用
    【main】
    Outer05 outer05 = new Outer05();
    outer05.f2();
class Outer05 {public void f2() {new Person() {@Overridepublic void hi() {System.out.println("匿名内部类重写hi~哈哈哈哈");}@Overridepublic void ok(String str) {System.out.println("匿名内部类重写ok~咳咳咳");super.ok(str);}}.ok("jackky");}
}class Person {public void ok(String str) {System.out.println("Person-ok()~"+str);}
}

5、最佳应用场景

(1)当作实参直接传递,简洁高效。

public class AnonymousInnerExercise {public static void main(String[] args) {f1(new IL(){@Overridepublic void show() {System.out.println("这是一幅名画");}});}public static void f1(IL il) {il.show();}
}interface IL {void show();
}

如果是传统方法:
编写一个类 —> 实现 IL —> 这个在编程领域被称为:硬编码

public class AnonymousInnerExercise {public static void main(String[] args) {f1(new Picture());}public static void f1(IL il) {il.show();}
}class Picture implements IL{@Overridepublic void show() {System.out.println("这是一幅名画");}
}interface IL {void show();
}

如果要修改show方法,硬编码方式中,只能在Picture 类修改,会影响到所有对象。

(2)练习

① 有一个铃声接口Bell,里面有个ring方法。(右图)
② 有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型(右图)
③ 测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
④ 再传入另一个匿名内部类(对象),打印:小伙伴上课了

public class AnonymousInnerExercise02 {public static void main(String[] args) {Cellphone cellphone = new Cellphone();cellphone.alarmclock(new Bell() {@Overridepublic void ring() {System.out.println("懒猪起床了");}});cellphone.alarmclock(new Bell() {@Overridepublic void ring() {System.out.println("小伙伴上课了");}});}
}
interface Bell {void ring();
}class Cellphone {public void alarmclock(Bell bell) {bell.ring();}
}

在这里插入图片描述
匿名内部类涉及到(1)继承(2)多态(3)动态绑定(4)内部类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/228651.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【问题系列】消费者与MQ连接断开问题解决方案(二)

1. 问题描述 当使用RabbitMQ作为中间件,而消费者为服务时,可能会出现以下情况:在长时间没有消息传递后,消费者与RabbitMQ之间出现连接断开,导致无法处理新消息。解决这一问题的方法是重启Python消费者服务,…

与珎同行录-开篇-231129

与珎同行录-开篇 珎就是对陪伴并帮助我写代码的AI的昵称 能不能读懂这个绕口令问题呢? 连续的椎体的相邻椎体质心的相邻质心的质心作为当前质心所在的椎体的质心, 该质心的方向代表该椎体的上下方向 如何代码实现呢? 还是没看懂…好吧最终的算法是:

Python缺失值处理实现

在数据处理相关工作中,读取的数据中常常会有缺失值的情况,为顺利进行后续的操作,需要首先对缺失值进行处理,处理的方式一般为删除或填充,Python中提供了专门的工具包,可以方便地进行实现。读取操作可以由pa…

基于+spring boot+layui+Mysql开发的就业信息管理系统

基于spring bootlayuiMysql开发的就业信息管理系统 项目介绍💁🏻 就业信息管理系统项目背景介绍 随着社会经济的发展和就业市场的不断变化,就业信息管理成为了各高校和企业亟待解决的问题。为了满足广大毕业生和用人单位的需求,我…

手把手教你如何实现List——ArrayList

目录 前言: 线性表 顺序表 接口的实现 一. 打印顺序表 二.新增元素,默认在数组最后新增 三.在 pos 位置新增元素 四.判定是否包含某个元素 五. 查找某个元素对应的位置 六.获取 pos 位置的元素 七.给 pos 位置的元素设为 value 八.删除第一次出现的关键字k…

Prometheus的详细部署

普罗米修斯下载网址: Download | Prometheus 准备两台机器: 192.168.58.152 prometheus 192.168.58.142 node_exporter 关闭防火墙和selinux: [rootlocalhost ~]# setenforce 0 && systemctl stop firewalld[rootlocalhost ~]# seten…

Baby-Step Giant-Step Homomorphic DFT

参考文献: [CT65] Cooley J W, Tukey J W. An algorithm for the machine calculation of complex Fourier series[J]. Mathematics of computation, 1965, 19(90): 297-301.[Shoup95] Shoup V. A new polynomial factorization algorithm and its implementation[…

【数据结构 —— 二叉树的链式结构实现】

数据结构 —— 二叉树的链式结构实现 1.树的概念及其结构1.1.树概念1.2.树的结构1.3树的相关概念1.4.树的表示1.5. 树在实际中的运用(表示文件系统的目录树结构) 2.二叉树的概念及其结构2.1二叉树的概念2.2.现实中的二叉树:2.3. 特殊的二叉树…

国产操作系统-银河麒麟V10

一、介绍 银河麒麟操作系统隶属于麒麟软件,麒麟软件是专业从事国产操作系统研发和产业化的企业,面向通用和专用领域打造安全创新的国产操作系统产品和相应解决方案,旗下拥有银河麒麟、中标麒麟、星光麒麟三大产品品牌。 麒麟软件官方网站地…

Shell条件变量练习

1.算数运算命令有哪几种? (1) "(( ))"用于整数运算的常用运算符,效率很高 [rootshell scripts]# echo $((24*5**2/8)) #(( ))2452814 14 (2) "$[ ] "用于整数运算 [rootshell scripts]# echo $[24*5**2/8] #[ ]也可以运…

Windows10系统卸载服务和删除服务

记录一下Windows10系统卸载服务和删除服务 最近在使用自己win电脑的时候 发现服务里存在很久之前就没有使用的应用,对应的文件夹也都已经删除了,但是在win服务里一直存在,不知道会不会影响性能,看着吧还是强迫自己删掉好一些&…

解决:SyntaxError: Non-UTF-8 code starting with À in file but no encoding declared

解决:SyntaxError: Non-UTF-8 code starting with in file but no encoding declared 文章目录 解决:SyntaxError: Non-UTF-8 code starting with in file but no encoding declared背景报错问题报错翻译报错原因解决方法使用utf-8格式使用gbk格式今天…