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

news2024/11/24 16:25:17

匿名内部类

    • 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)内部类

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Alibaba Java诊断工具Arthas查看Dubbo动态代理类

原创/朱季谦 阅读Dubbo源码过程中&#xff0c;会发现&#xff0c;Dubbo消费端在做远程调用时&#xff0c;默认通过 Javassist 框架为服务接口生成动态代理类&#xff0c;调用javassist框架下的JavassistProxyFactory类的getProxy(Invoker invoker, Class<?>[] interfac…

GO 集成Prometheus

一、Prometheus介绍 Prometheus&#xff08;普罗米修斯&#xff09;是一套开源的监控&报警&时间序列数据库的组合&#xff0c;起始是由SoundCloud公司开发的。随着发展&#xff0c;越来越多公司和组织接受采用Prometheus&#xff0c;社会也十分活跃&#xff0c;他们便…

GAN:GAN论文学习

论文&#xff1a;https://arxiv.org/pdf/1406.2661.pdf 发表&#xff1a;2014 一、GAN简介&#xff1a;Generative Adversarial Network GAN是由Ian Goodfellow于2014年提出&#xff0c;GAN&#xff1a;全名叫做生成对抗网络。GAN的目的就是无中生有&#xff0c;以假乱真。 …

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

java开发需要掌握的maven相关知识和Junit单元测试

maven简介 什么是maven&#xff1a; maven是一款管理和构建java项目的工具&#xff0c;是apache旗下的一个开源项目。 maven的作用&#xff1a; 依赖管理&#xff1a; 方便快捷的管理项目依赖的资源&#xff08;jar包&#xff09;。 项目构建&#xff1a; 标准化的跨平台&#…

MacBook如何远程控制华为手机?

将手机屏幕投影到电脑上可以提供更大的屏幕空间&#xff0c;方便观看电影、浏览照片、阅读文档等。然而&#xff0c;除了想将手机投屏到电脑&#xff0c;还想要在电脑上直接操作手机&#xff0c;有方法可以实现吗&#xff1f; 现在使用AirDroid Cast的远程控制手机功能就可以实…

【数据结构】树与二叉树(廿五):树搜索给定结点的父亲(算法FindFather)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲a. 算法FindFatherb. 算法解析c. 代码实现 3. 代码整合 5.3.1 树的存储结构 5. 左儿子右兄弟链接结构 【数据结构】树与二叉树&#xff08;十九&…

Linux dig指令的十三种用法

文章目录 dig指令有哪些作用dig 具体用法推荐阅读 dig指令有哪些作用 DIG命令(Domain Information Groper命令)是一个网络工具&#xff0c;具有基本的命令行接口&#xff0c;用于进行不同的DNS(域名系统)查询。您可以使用DIG命令: 诊断您的域名服务器。检查所有这些服务器或每…

《数据结构与测绘程序设计》试题详细解析(仅供参考)

一. 选择题&#xff08;每空2分&#xff0c;本题共30分&#xff09; &#xff08;1&#xff09;在一个单链表中&#xff0c;已知q所指结点是p所指结点的前驱结点&#xff0c;若在q和p之间插入结点s&#xff0c;则执行( B )。 A. s->nextp->next; p->nexts; …

Qt路径和Anaconda中QT路径冲突(ubuntu系统)

最近做一个项目需要配置QT库&#xff0c;本项目配置环境如下&#xff1a; Qt version 5 Operating system, version and so on ubuntu 20.04 Description 之前使用过anaconda环境安装过QT5&#xff0c;所以在项目中CMakeLists文件中使用find_package时候&#xff0c;默认使用An…

C#,数值计算——插值和外推,径向基函数插值(RBF_inversemultiquadric)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class RBF_inversemultiquadric : RBF_fn { private double r02 { get; set; } public RBF_inversemultiquadric(double scale 1.0) { this.r02 Globals.SQR(scale); …

Spring Boot实现图片上传和展示

Spring Boot实现图片上传和展示 本文将介绍如何使用Spring Boot框架搭建后端服务&#xff0c;实现接收前端上传的图片并保存到resources/images目录下。同时&#xff0c;我们还将展示如何在前端编写一个HTML页面&#xff0c;实现上传图片和从resources/images目录下获取图片并…

PHP+vue+elementui高校学生社团信息管理系统o7q4a

社团是由高校用户依据兴趣爱好自愿组成&#xff0c;按照章程自主开展活动的用户组织。高校社团是实施素质教育的重要途径和有效方式&#xff0c;在加强校园文化建设、提高用户综合素质、引导用户适应社会、促进用户交流等方面发挥着重要作用&#xff0c;是新形势下有效凝聚用户…

[Python入门系列之十一]在windows上安装OpenCV

1-安装OpenCV 如果是python3.7–python3.9(已测试)&#xff0c;直接安装即可 注&#xff1a;conda需要先激活虚拟环境后再安装 pip install opencv-python如果安装速度慢&#xff0c;使用下面的指令&#xff1a; pip install opencv-python -i https://pypi.tuna.tsinghua.e…

AIGC-文生视频

stable diffusion&#xff1a; stable diffusion原理解读通俗易懂&#xff0c;史诗级万字爆肝长文&#xff0c;喂到你嘴里 - 知乎个人网站一、前言&#xff08;可跳过&#xff09;hello&#xff0c;大家好我是 Tian-Feng&#xff0c;今天介绍一些stable diffusion的原理&#…

Micropython STM32F4外部中断实验

Micropython STM32F4外部中断实验 &#x1f4cc;固件刷可参考前面一篇《STM32刷Micropython固件参考指南》&#x1f33f; 相关篇《Micropython STM32F4入门点灯》&#x1f4cd;固件下载&#xff1a;https://micropython.org/download/?mcustm32f4&#x1f516;本例程基于STM32…

「C++」红黑树的插入(手撕红黑树系列)

&#x1f4bb;文章目录 &#x1f4c4;前言红黑树概念红黑树的结构红黑树节点的定义红黑树的定义红黑树的调整 红黑树的迭代器迭代器的声明operator( )opeartor--( ) 完整代码 &#x1f4d3;总结 &#x1f4c4;前言 作为一名程序员相信你一定有所听闻红黑树的大名&#xff0c;像…

【区块链】产品经理的NFT初探

常见的FT如比特币&#xff08;BTC&#xff09;&#xff0c;以太币&#xff08;ETH&#xff09;等&#xff0c;两个代币之间是完全可替换的。而NFT具有唯一性&#xff0c;不可以互相替换。本文作者对NET的发展现状、相关协议、应用场景等方面进行了分析&#xff0c;一起来看一下…

修复debain/ Ubuntu 中的“密钥存储在旧版 trust.gpg 密钥环中”问题

如果您在 Ubuntu 22.04 及更高版本中使用 PPA 或添加外部存储库&#xff0c;您很可能会看到如下消息&#xff1a; W: https://packagecloud.io/slacktechnologies/slack/debian/dists/jessie/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg),…

springcloud nacos配置优先级研究及配置管理最佳实践

目录 背景工具版本SpringCloud配置存放位置及相应优先级代码中nacosjar包外挂 多种配置共同存在时的优先级项目配置管理最佳实践无nacos的情况有nacos的情况 参考文献 背景 公司有很多应用是基于SpringBoot/SpringCloud开发。由于在配置文件中经常会涉及数据库账号密码之类的敏…