Java进阶学习笔记19——内部类

news2025/5/25 12:00:17

1、 内部类:

是类中五大成分之一(成员变量、方法、构造函数、内部类、代码块),如果一个类定义在另一个 类的内部,这个类就是内部类。

场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。

内部类的四种形式:

成员内部类:了解

静态内部类:了解

局部内部类:了解

匿名内部类:重点

成员内部类:

就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法。

Outer类:

内含内部类:

package cn.ensource.d1_inner_class1;

public class Outer {
    private int age = 99;
    public static String a;

    // 普通成员内部类
    public class Inner{
        private String name;
        private int age = 88;
        public static String schoolName;  // JDK16才支持静态成员的

        public void test() {
            System.out.println(age);
            System.out.println(a);

            int age = 66;
            // 66
            System.out.println(age);
            // 88
            System.out.println(this.age);
            // 99
            System.out.println(Outer.this.age);

        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

测试类:

package cn.ensource.d1_inner_class1;

public class Test {
    public static void main(String[] args) {
        // 目标:了解成员内部类
        Outer.Inner in = new Outer().new Inner();
        in.test();
    }
}

注意:

JDK16之前,成员内部类中不能定义静态成员,JDK16开始也可以定义静态成员了。

创建对象的格式:

成员内部类中访问其他成员的特点:

1)和前面学过的实例方法一样,成员内部类的实例方法中,同样可以直接访问外部类的实例成员、静态成员。

2)可以在成员内部类的实例方法中,拿到当前外部类对象,格式: 外部类名.this

静态内部类:

所谓静态内部类,有static修饰符的内部类,属于外部类自己持有。

静态内部类是外部类持有的。

Outer类:包含静态内部类:

package cn.ensource.d1_inner_class2;

public class Outer {
    private int age;
    public static String schoolName;
    // 静态内部类
    public static class Inner {
        private String name;
        public static int a;

        public void test() {
//            System.out.println(age);  // 只能通过外部类对象访问
            System.out.println(schoolName);

        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public static int getA() {
            return a;
        }

        public static void setA(int a) {
            Inner.a = a;
        }
    }

    public static void test2() {
        System.out.println(schoolName);
//        System.out.println(age);

    }
}

 测试类:

package cn.ensource.d1_inner_class2;

public class Test {
    public static void main(String[] args) {
        // 目标:了解静态内部类
        Outer.Inner in = new Outer.Inner();
        in.getName();
        in.test();
    }
}

特别要注意的是:

可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。

外部类的实例成员只能通过外部类对象来访问。

局部内部类:

局部内部类是定义在方法中,代码块中,构造器等执行体中。

匿名内部类:(重点)

就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字。

package d3_inner_class3;

public class Test {
    public static void main(String[] args) {
        // 目标:掌握匿名内部类,并掌握其作用
        Animal a = new Cat();   // 创建子类对象
        a.cry();

    }
}

class Cat extends Animal {

    @Override
    public void cry() {
        System.out.println("喵喵~");
    }
}

abstract class Animal {
    public abstract void cry();
}

进化:

package d3_inner_class3;

public class Test {
    public static void main(String[] args) {
        // 目标:掌握匿名内部类,并掌握其作用
//        Animal a = new Cat();   // 创建子类对象
//        a.cry();

        // 我们只要创建一下子类对象就可以了,不需要经常性的创建子类
        // 匿名内部类
        // 把这个匿名内部类编译成一个子类,然后会立即创建一个子类出来
        Animal a = new Animal() {

            @Override
            public void cry() {
                System.out.println("喵喵~");
            }
        };
        a.cry();
    }
}

class Cat extends Animal {

    @Override
    public void cry() {
        System.out.println("喵喵~");
    }
}

abstract class Animal {
    public abstract void cry();
}

匿名内部类的概念。

匿名内部类本质上是不是一个子类呢?

反编译可以看到这个匿名类是Animal的子类。

编译生成一个匿名的构造方法。

并且有内部方法cry方法。

特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象。

作用:用于更方便地创建一个子类对象。

匿名内部类的常见使用场景:

通常作为一个参数传递给方法。

package d3_inner_class3;

public class Test2 {
    public static void main(String[] args) {
        // 目标:掌握匿名内部类的使用场景:
        Swimming s1 = new Swimming(){

            @Override
            public void swim() {
                System.out.println("狗游泳!");
            }
        };
        go(s1);
        Swimming s2 = new Swimming() {

            @Override
            public void swim() {
                System.out.println("猫游泳!");
            }
        };
        go(s2);
    }

    // 设计一个方法,可以接收swimming接口的一切实现类对象进来参加游泳比赛
    // go 表示开始参加比赛
    public static void go(Swimming s) {
        System.out.println("开始----------");
        s.swim();
    }
}

// 猫和狗都要参加有用比赛
interface Swimming{
    void swim();
}

匿名内部类有啥特点:

匿名内部类本质上就是一个子类,并会立即创建出一个子类对象。

匿名内部类有啥作用、应用场景?

可以更方便创建出一个子类对象。

匿名内部类通常作为一个参数传递给方法。

拓展:

package cn.ensource.d4_inner_class5;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Test {
    public static void main(String[] args) {
        // 拓展:内部类在开发中的真实使用场景
        // GUI编程:
        // 1. 创建窗口
        JFrame win = new JFrame("登录");
        JPanel panel = new JPanel();
        win.add(panel);

        JButton btn = new JButton("登录");
        panel.add(btn);

        // 给按钮绑定单击事件监听器
        // 调别人的匿名内部类,需要用的时候才用
        // 真实应用场景
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(win, "登录一下");
            }
        });
        
        win.setSize(400, 400);
        win.setLocationRelativeTo(null);
        win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        win.setVisible(true);
    }
}

最终目的是为了简化代码。

箭头语法后面会讲得。

匿名内部类,我们需要的时候才会用。

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

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

相关文章

[笔试训练](三十三)097:跳台台阶扩展问题098:包含不超过两种字符的最长子串099:字符串的排列

目录 097:跳台台阶扩展问题 098:包含不超过两种字符的最长子串 099:字符串的排列 097:跳台台阶扩展问题 题目链接:跳台阶扩展问题_牛客题霸_牛客网 (nowcoder.com) 题目: 题解: 规律题: 1.跳上n级台阶的跳法等于前面1~(n-1)级台阶跳法的总和1。 2.跳…

[5] CUDA线程调用与存储器架构

CUDA线程调用与存储器架构 前几节简单讲了如何编写CUDA程序,利用GPU的处理能力并行执行多个线程和块。之前所有程序里的线程是相互独立的,没有多个线程之间的通信多是实际应用程序需要中间线程之间的通信,本文将仔细讲解线程调用以及CUDA的分…

Gradle的settings.gradle.kts你真的理解吗?

你还在用.gradle文件吗?例如build.gradle、settings.gradle,那么你就out了。现在我们有必要了解一下kts脚本了。在Android项目中,默认有3个文件可以替换成kts脚本,即project的build.gradle、app模块的build.gradle和project的sett…

关于在子线程中获取不到HttpServletRequest对象的问题

这篇文章主要分享一下项目里遇到的获取request对象为null的问题,具体是在登录的时候触发的邮箱提醒,获取客户端ip地址,然后通过ip地址定位获取定位信息,从而提示账号在哪里登录。 但是登录却发现获取request对象的时候报错了。 具…

数据插值之朗格朗日插值(一)

目录 一、引言 二、代码实现 2.1 Lagrange插值求插值多项式: 代码解析: 1.vpa解释 2.ploy(x)解释: 3.conv()解释 4.poly2sym()解释 2.2 Lagrange插值求新样本值和误差估计: 代码解析&…

鲁教版七年级数学上册-笔记

文章目录 第一章 三角形1 认识三角形2 图形的全等3 探索三角形全等的条件4 三角形的尺规作图5 利用三角形全等测距离 第二章 轴对称1 轴对称现象2 探索轴对称的性质4 利用轴对称进行设计 第三章 勾股定理1 探索勾股定理2 一定是直角三角形吗3 勾股定理的应用举例 第四章 实数1 …

C++技能进阶指南——多态语法剖析

前言:多态是面向对象的三大特性之一。顾名思义, 多态就是多种状态。 那么是什么的多种状态呢? 这里的可能有很多。比如我们去买火车票, 有普通票, 学生票; 又比如我们去旅游, 有儿童票&#xff…

心链2---前端开发(整合路由,搜索页面,用户信息页开发)

心链——伙伴匹配系统 接口调试 说书人📖:上回书说到用了两种方法查询标签1.SQL查询,2.内存查询;两种查询效率是部分上下,打的是难解难分,是时大地皴裂,天色聚变,老祖斟酌再三最后决…

数据库-SQL性能分析

SQL执行频率 慢查询日志 慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有 SQL语句的日志。 MySQL的慢查询日志默认没有开启,我们可以查看一下系统变量 slow_query_l…

leetcode328. 奇偶链表,附详细解析和代码注释

leetcode328. 奇偶链表 给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。 第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。 请注意&#xff0…

初出茅庐的小李博客之用MQTT.fx软件进行消息发布与订阅【 基于EMQX Cloud】

MQTT.fx软件使用简单介绍 MQTT.fx 的软件界面如下图所示,最上方为 MQTT Broker 连接地址栏,及其连接配置。其下方功能 Tabs 含有 Publish 发布栏、Subscribe 订阅栏、Scripts 脚本栏、Broker Status 状态消息栏、Log 日志信息控制栏。 连接之前要明确几…

Distributed Transactions Mit 6.824

Topic1:distributed transactions concurrency control atomic commit 传统计划:事务 程序员标记代码序列的开始/结束作为事务。 事务示例 x 和 y 是银行余额——数据库表中的记录。x 和 y 位于不同的服务器上(可能在不同的银行&#x…

NDIS小端口驱动(九)

PCIe设备难免会遇到一些重置设备的请求,例如重置总线的时候,但是由于NIC网卡的多样性,重置设备确实也有许多要注意的地方,另外还有一些包含WDM的NDIS驱动 微型端口驱动程序硬件重置 微型端口驱动程序必须向 NdisMRegisterMinipo…

10款免费黑科技软件,强烈推荐!

1.AI视频生成——巨日禄 网页版https://aitools.jurilu.com/ "巨日禄 "是一款功能强大的文本视频生成器,可以快速将文本内容转换成极具吸引力的视频。操作简单,用户只需输入文字,选择喜欢的样式和模板, “巨日禄”就会…

qemu+gdb调试linux内核

打开CONFIG_DEBUG_INFO,编译内核 通过图形菜单配置该宏,执行make menuconfig。 kernel hacking —> compile-time checks and compiler options —> compile the kernel with debug info 验证是否打开成功,grep -nr “CONFIG_DEBUG_INFO” .config。 打开成功,然后…

初识Spring Boot

初识Spring Boot SpringBoot是建立在Spring框架之上的一个项目,它的目标是简化Spring应用程序的初始搭建以及开发过程。 对比Spring Spring Boot作为Spring框架的一个模块,旨在简化Spring应用程序的初始搭建和开发过程,以下是Spring Boot相对于传统Spri…

【通义千问—Qwen-Agent系列2】案例分析(图像理解图文生成Agent||多模态助手|| 基于ReAct范式的数据分析Agent)

目录 前言一、快速开始1-1、介绍1-2、安装1-3、开发你自己的Agent 二、基于Qwen-Agent的案例分析2-0、环境安装2-1、图像理解&文本生成Agent2-2、 基于ReAct范式的数据分析Agent2-3、 多模态助手 附录1、agent源码2、router源码 总结 前言 Qwen-Agent是一个开发框架。开发…

iZotope RX 11 for Mac:音频修复的终极利器

在音频处理的世界里,纯净与清晰是每一个创作者追求的目标。iZotope RX 11 for Mac,这款专为Mac用户打造的音频修复软件,凭借其卓越的音频修复能力和丰富的功能,已经成为众多音频工程师和音乐制作人的首选工具。 iZotope RX 11 for…

线程生命周期

创建线程的两种方法 1.继承Thread类 2.实现Runnable接口 线程从创建到消亡分为新建、就绪、运行、阻塞、死亡5种状态。 新建状态 创建一个线程就处于新建状态。此时线程对象已经被分配了内存空间,并且私有数据也被初始化,但是该线程还不能运行。 就…