匿名内部类(内部类) - 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{
    @Override
    public void cry() {
        System.out.println("老虎叫唤···");
    }
}

class Dog implements IA{
    @Override
    public 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() {
            @Override
            public void cry() {
                System.out.println("老虎喊叫···");
            }
        };
        tiger_.cry();
    }
}

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

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

class XXXX implements IA {
	@Override
    public 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 {
	@Override
    public void test() {
         System.out.println("匿名内部类重写了Fathter中的test方法");
    }
}
class Outer04_ {
    private int n1 = 10;
    public void method() {
        Father father = new Father("jack") {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public void hi() {
                System.out.println("匿名内部类重写hi~");
            }
        };
        //p的编译类型 Person
        //p的运行类型 Outer05$1
        p.hi();//动态绑定
    }
}

class Person {
    public void hi() {
        System.out.println("Person-hi()~");
    }
}
  • 方法二 直接调用,匿名内部类本身也是返回对象
class Outer05 {
    public void f2() {
        new Person() {
            @Override
            public void hi() {
                System.out.println("匿名内部类重写hi~哈哈哈哈");
            }
        }.hi();
    }
}

在这里插入图片描述

  • 带参数调用
    【main】
    Outer05 outer05 = new Outer05();
    outer05.f2();
class Outer05 {
    public void f2() {
        new Person() {
            @Override
            public void hi() {
                System.out.println("匿名内部类重写hi~哈哈哈哈");
            }
            @Override
            public 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(){
            @Override
            public 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{
    @Override
    public 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() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });

        cellphone.alarmclock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}
interface Bell {
    void ring();
}

class Cellphone {
    public void alarmclock(Bell bell) {
        bell.ring();
    }
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Coremail出席2023信息技术应用创新论坛

11月25日,2023信息技术应用创新论坛在常州开幕。江苏省工业和信息化厅副厅长池宇、中国电子工业标准化技术协会理事长胡燕、常州市常务副市长李林等领导出席论坛并致辞。中国工程院院士郑纬民出席并作主题报告。来自产学研用金等各界的千余名代表参加本次论坛。作为…

【仿写C++中的move函数和forward函数】

仿写实现move函数 一、值的类型 1.左值 描述:能够取地址的值成为左值 int a 10; const int b 15; int *pa &a; const int *pb &b;2.纯右值 描述:赤裸裸的字面值 eg(false , 3 , 12.23等) int a 13; int *p &a; //取a的地址 int …

Redis缓存设计典型问题

目录 缓存穿透 缓存失效(击穿) 缓存雪崩 热点缓存key重建优化 缓存与数据库双写不一致 缓存穿透 缓存穿透是指查询一个根本不存在的数据, 缓存层和存储层都不会命中, 通常出于容错的考虑, 如果从存储层查不到数据…

kubenetes--kube-proxy实现负载均衡

一、Linux网络收包 要了解kube-proxy如何实现负载均衡,要先了解Linux网络收包机制,kube-proxy利用Linux的内核实现的负载均衡。 在TCP/IP网络分层模型里,整个协议栈被分成了物理层、链路层、网络层,传输层和应用层。物理层对应的…

ESP Multi-Room Music 方案:支持音频实时同步播放 实现音乐互联共享

项目背景 随着无线通信技术的发展,针对不同音频应用领域的无线音频产品正不断涌现。近日,乐鑫科技推出了基于 Wi-Fi 的多扬声器互联共享音乐通信协议——ESP Multi-Room Music 方案。该方案使用乐鑫自研的基于 Wi-Fi 局域网的音频同步播放技术&#xff…

基于SSM框架的合同服务管理系统设计与实现

基于SSM框架的合同服务管理系统的设计与实现 摘要:当今社会,各行各业都离不开计算机软件的推广,销售,运营各方面,有些中小型企业没有技术与能力开发和维护一款软件来运营,这时催生很多软件外包公司的产生。…

【Electron】上下键切换消息

需求: 如图,需要监听上下键切换消息 Electron 注册 全局快捷键【globalShortcut】监听 在focus注册 在blur 注销 如苹果系统在使用某个软件(focus)时 右上角会有应用标题 Electron 代码: win.on(focus, ()>{globalShortcut.register(U…

建筑木模板厂家批发

在建筑施工中,木模板是一种常见且重要的施工材料,用于搭建混凝土浇筑的支撑结构。选择合适的建筑木模板厂家进行批发,对于施工质量和效率至关重要。本文将介绍建筑木模板厂家批发的重要性,并推荐贵港市能强优品木业作为专业的建筑…

【数据结构复习之路】树和二叉树(严蔚敏版)万字详解主打基础

专栏:数据结构复习之路 复习完上面四章【线性表】【栈和队列】【串】【数组和广义表】,我们接着复习 树和二叉树,这篇文章我写的非常详细且通俗易懂,看完保证会带给你不一样的收获。如果对你有帮助,看在我这么辛苦整理…

阿里云语雀频繁崩溃,有什么文档管理工具是比较稳定的?

10月23 日14:00左右,蚂蚁集团旗下的在线文档编辑与协同工具语雀发生服务器故障,在线文档和官网都无法打开。直到当天晚上22:24,语雀服务才全部恢复正常。从故障发生到完全恢复正常,语雀整个宕机时间将近 8 小时,如此长…

深度学习毕设项目 基于生成对抗网络的照片上色动态算法设计与实现 - 深度学习 opencv python

文章目录 1 前言1 课题背景2 GAN(生成对抗网络)2.1 简介2.2 基本原理 3 DeOldify 框架4 First Order Motion Model 1 前言 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求&am…

PS最新磨皮软件Portraiture4.1.2

Portraiture是一款好用的PS磨皮滤镜插件,拥有磨皮美白的功能,操作也很简单,一键点击即可实现美白效果,软件还保留了人物的皮肤质感让照片看起来更加真实。portraiture体积小巧,不会占用过多的电脑内存哦。 内置了多种…

交流负载测试使用场景

交流负载测试是一种在特定环境下,对电力设备、汽车电子部件,工业自动化设备、网络设备、家电产品,航空航天设备以及医疗器械等产品进行测试的方法,该测试的目的是评估这些设备在实际运行条件下的性能和可靠性。 1电力设备测试 交…

基于SSM实现的叮当书城

一、系统架构 前端:jsp | jquery | layui 后端:spring | springmvc | mybatis 环境:jdk1.7以上 | mysql | maven 二、代码与数据库 三、功能介绍 01. 系统首页 02. 商品分类 03. 热销 04. 新品 05. 注册 06. 登录 07. 购物车 08. 后台-首页 …

HTTP协议,Web框架回顾

HTTP 请求协议详情 -请求首行---》请求方式,请求地址,请求协议版本 -请求头---》key:value形式 -referer:上一次访问的地址 -user-agenet:客户端类型 -name:lqz -cookie&…

c语言,输入整数n(行数,本例为4),按照如下规则打印数字图片 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16

c语言&#xff0c;输入整数n(行数&#xff0c;本例为4&#xff09;&#xff0c;按照如下规则打印数字图片 1 5 9 13 2 6 10 14 3 7 11 15 4 8 12 16 以下是使用C语言编写的程序&#xff0c;根据输入的行数打印数字图片的规则&#xff1a; #include <stdio.h>int main() …

lack——主页前后端开发优化(精华:java多线程实现数据插入)

lack——主页前后端开发优化 前端开发主页 最容易的方式&#xff1a;list列表<template><van-cardv-for"user in props.userList":desc"user.profile":title"${user.username} (${user.planetCode})":thumb"user.avatarUrl"…

静态方法和属性的经典使用-单例设计模式

单例设计模式 一、设计模式二、单例模式1、饿汉式2、懒汉式3、区别 单例设计模式是静态方法和属性的经典使用。 一、设计模式 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱&#xff0c;不同的棋局&…

基于隐马尔可夫模型的一种流水印

文章信息 论文题目&#xff1a;An Invisible Flow Watermarking for Traffic Tracking: A Hidden Markov Model Approach 期刊&#xff08;会议&#xff09;&#xff1a;ICC 2019 - 2019 IEEE International Conference on Communications (ICC) 时间&#xff1a;2019 级别&am…

linux调用github代码文件

一&#xff0c;建库 默认建好库 默认linux已安装好git 二&#xff0c;生成SSH公钥 1&#xff0c;选这 2进教程&#xff0c;看怎么生成公钥的 根据下图教程&#xff0c;得到key&#xff0c;添加到github中&#xff01;具体教程&#xff0c;进github看 三。调用 gitssh链…