【潜意识Java】Java匿名内部类深入笔记总结,助力开启高效编程新征程。

目录

一、匿名内部类是什么

(一)概念引入

(二)语法结构

二、匿名内部类的优势

(一)简洁的代码表达

(二)灵活的功能实现

三、匿名内部类在实际场景中的应用

(一)图形绘制系统

(二)事件驱动编程

四、匿名内部类与局部内部类、成员内部类的比较

(一)与局部内部类的区别

(二)与成员内部类的区别

五、匿名内部类的注意事项

(一)访问外部变量的限制

(二)调试的复杂性

六、总结


924123e4251540e2a16c4398ad6d1193.gif

亲爱的家人们,今天我要给你们讲讲 Java 编程里一个特别神奇的东西 —— 匿名内部类。它就像是一位隐匿在代码世界中的高手,平时不怎么引人注目,但一旦出手,就能让我们的代码变得更加简洁、灵活,而且功能强大。接下来,我会带着你们一步步揭开它神秘的面纱,看看它到底有什么奇妙之处。

一、匿名内部类是什么

(一)概念引入

简单来说,匿名内部类就是没有名字的内部类。它通常是在创建一个对象的同时,定义这个对象所属类的具体实现。想象一下,你去一家餐厅吃饭,你不需要知道厨师的名字,只需要告诉服务员你想吃什么,厨师就会按照你的要求做出美味的菜肴。匿名内部类就像是这位不知名的厨师,在你需要一个特定功能的对象时,它能迅速地为你创建一个满足需求的实例,而不需要你事先定义一个具体的类名。

a662e939426740ae9b006771f43cdeb8.jpg

例如,我们有一个 Shape 接口,定义了一个 draw 方法:

```java
interface Shape {
    void draw();
}

```

现在,我们想要创建一个实现了 Shape 接口的类的对象,并调用它的 draw 方法,使用匿名内部类可以这样做:

```java
public class Main {
    public static void main(String[] args) {
        Shape circle = new Shape() {
            @Override
            public void draw() {
                System.out.println("画一个圆形");
            }
        };
        circle.draw();
    }
}

```

f33e8ad139ac4ff39bbd1b211da9de25.jpg

在这个例子中,new Shape() {... } 这部分就是匿名内部类的定义,它实现了 Shape 接口的 draw 方法,然后我们创建了这个匿名内部类的实例,并将其赋值给 Shape 类型的变量 circle,最后调用了 draw 方法,输出了 “画一个圆形”。

(二)语法结构

匿名内部类的语法结构通常是 new 接口名或抽象类名 () {... } 或者 new 父类名 () {... }。如果是实现接口,就像上面的例子,在大括号内实现接口的所有方法;如果是继承抽象类或普通类,在大括号内可以重写父类的方法,或者定义新的方法(如果需要的话)。需要注意的是,匿名内部类只能实现一个接口或者继承一个类,这是它的语法限制。

二、匿名内部类的优势

(一)简洁的代码表达

匿名内部类最大的优势之一就是能够让代码更加简洁。以前面的 Shape 接口为例,如果我们不使用匿名内部类,而是先定义一个实现 Shape 接口的具体类,比如 Circle 类:

```java
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

```

然后在 main 方法中使用这个类:

```java
public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle();
        circle.draw();
    }
}

```

可以看到,使用匿名内部类可以省去定义 Circle 类的代码,直接在创建对象的地方定义类的实现,使得代码更加紧凑,特别是对于一些只需要使用一次的类的实现,这种简洁性尤为明显,让我们的代码看起来更加清爽,减少了不必要的类定义和文件数量。

(二)灵活的功能实现

匿名内部类还具有很强的灵活性,它可以根据不同的场景快速地实现不同的功能。例如,我们有一个 Button 类,它有一个 setOnClickListener 方法,用于设置按钮的点击事件处理逻辑:

```java
class Button {
    public void setOnClickListener(OnClickListener listener) {
        // 这里假设已经有处理点击事件的机制,只是为了演示
        listener.onClick();
    }
}

interface OnClickListener {
    void onClick();
}

```

现在,我们可以使用匿名内部类为不同的按钮设置不同的点击事件处理逻辑:

```java
public class Main {
    public static void main(String[] args) {
        Button button1 = new Button();
        button1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick() {
                System.out.println("按钮 1 被点击了,执行操作 A");
            }
        });

        Button button2 = new Button();
        button2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick() {
                System.out.println("按钮 2 被点击了,执行操作 B");
            }
        });
    }
}

```

在这个例子中,我们通过匿名内部类为两个按钮分别设置了不同的点击事件处理逻辑,而不需要为每个按钮的点击事件都定义一个独立的类,使得代码更加灵活,能够轻松地应对各种不同的交互需求,提高了代码的复用性和适应性。

4a3e768724224a738c24dc4137351203.jpg

三、匿名内部类在实际场景中的应用

(一)图形绘制系统

在一个图形绘制系统中,我们可能有各种不同的图形,如圆形、矩形、三角形等,它们都实现了一个 Shape 接口,该接口定义了 draw 方法。使用匿名内部类,我们可以方便地在需要绘制图形的地方直接定义图形的绘制逻辑:

```java
import java.util.ArrayList;
import java.util.List;

interface Shape {
    void draw();
}

public class GraphicsSystem {
    public static void main(String[] args) {
        List shapes = new ArrayList<>();

        // 添加圆形
        shapes.add(new Shape() {
            @Override
            public void draw() {
                System.out.println("绘制一个红色的圆形");
            }
        });

        // 添加矩形
        shapes.add(new Shape() {
            @Override
            public void draw() {
                System.out.println("绘制一个蓝色的矩形");
            }
        });

        // 绘制所有图形
        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}

```

在这个例子中,我们使用匿名内部类创建了圆形和矩形的实例,并将它们添加到一个图形列表中,然后遍历列表绘制所有图形。这种方式使得添加新的图形变得非常容易,只需要在相应的地方使用匿名内部类定义新图形的绘制逻辑,而不需要创建大量的具体图形类,提高了图形绘制系统的扩展性和灵活性。

(二)事件驱动编程

在事件驱动编程中,匿名内部类被广泛应用于处理各种事件,如鼠标点击、键盘输入、窗口关闭等。例如,我们使用 Java 的 Swing 库创建一个简单的图形用户界面,当点击按钮时弹出一个消息框:

```java
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class GUIExample {
    public static void main(String[] args) {
        JFrame frame = new JFrame("匿名内部类示例");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton button = new JButton("点击我");
        button.addActionListener(new java.awt.event.ActionListener() {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent e) {
                JOptionPane.showMessageDialog(frame, "按钮被点击了!");
            }
        });

        frame.getContentPane().add(button);
        frame.pack();
        frame.setVisible(true);
    }
}

```

在这个例子中,我们使用匿名内部类实现了 ActionListener 接口,当按钮被点击时,会执行 actionPerformed 方法,弹出一个消息框。通过匿名内部类,我们可以将事件处理逻辑直接与按钮的添加动作绑定在一起,使代码更加简洁直观,同时也提高了代码的响应性和交互性。而且,如果我们需要为不同的按钮设置不同的点击事件处理逻辑,只需要使用不同的匿名内部类即可,非常方便灵活。

四、匿名内部类与局部内部类、成员内部类的比较

(一)与局部内部类的区别

局部内部类是定义在方法内部的类,它有自己的类名,可以在方法内部多次实例化,并且可以访问方法的局部变量(前提是这些变量是 final 或者事实上的 final)。而匿名内部类没有类名,它是在创建对象的同时定义类的实现,并且只能创建一个实例。例如:

```java
public class OuterClass {
    public void doSomething() {
        // 局部内部类
        class LocalInnerClass {
            public void localMethod() {
                System.out.println("这是局部内部类的方法");
            }
        }

        LocalInnerClass localInner1 = new LocalInnerClass();
        LocalInnerClass localInner2 = new LocalInnerClass();

        // 匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("这是匿名内部类实现的 run 方法");
            }
        };
    }
}

```

在这个例子中,LocalInnerClass 是局部内部类,可以创建多个实例,而匿名内部类创建的 Runnable 实例只有一个。

(二)与成员内部类的区别

内部类是定义在类内部的成员,它可以访问外部类的所有成员,包括私有成员,并且可以有各种访问修饰符。成员内部类有自己的类名,可以在外部类的多个方法中实例化和使用。而匿名内部类没有类名,它通常是为了满足某个特定的一次性需求而创建的,并且只能在创建它的地方使用。例如:

```java
public class OuterClass {
    private int outerVariable = 10;

    // 成员内部类
    class InnerClass {
        private int innerVariable = 20;

        public void innerMethod() {
            System.out.println("外部类变量:" + outerVariable);
            System.out.println("内部类变量:" + innerVariable);
        }
    }

    public void doSomething() {
        // 匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("这是匿名内部类实现的 run 方法");
            }
        };
    }
}

```

在这个例子中,InnerClass 是成员内部类,可以在 OuterClass 的其他方法中访问和使用,而匿名内部类创建的 Runnable 实例只在 doSomething 方法中使用。

五、匿名内部类的注意事项

(一)访问外部变量的限制

匿名内部类可以访问外部类的成员变量和方法,但是如果要访问外部方法的局部变量,这些局部变量必须是 final 或者事实上的 final(从 Java 8 开始)。这是因为匿名内部类的实例可能会在外部方法执行完毕后仍然存在,如果允许修改局部变量,可能会导致数据不一致的问题。例如:

```java
public class OuterClass {
    public void doSomething() {
        final int num = 10;
        // 匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("访问外部方法的局部变量 num:" + num);
            }
        };
    }
}

```

在这个例子中,numfinal 的,所以匿名内部类可以访问它。如果去掉 final 关键字,代码将无法编译通过(在 Java 8 以前的版本中),或者会出现警告(在 Java 8 及以后的版本中,因为虽然可以访问,但不允许修改)。

(二)调试的复杂性

由于匿名内部类没有类名,在调试代码时可能会带来一些困难。当出现问题时,调试工具可能无法准确地显示匿名内部类的相关信息,例如类名、行号等,这使得定位问题变得更加复杂。因此,在使用匿名内部类时,如果代码比较复杂,可能需要更加仔细地编写和测试代码,以减少出现问题的可能性。同时,也可以考虑在必要时使用有类名的内部类或普通类来代替匿名内部类,以便更好地进行调试和维护。

六、总结

亲爱的家人们,通过以上的介绍,相信你们对 Java 中的匿名内部类有了一个全面而深入的了解。匿名内部类虽然看起来有点神秘,但它确实是一个非常强大的工具,能够让我们的代码更加简洁、灵活和高效。无论是在图形绘制、事件处理还是其他各种编程场景中,合理地运用匿名内部类都能够帮助我们更好地实现功能,提高代码的质量和开发效率。在今后的 Java 编程学习和实践中,希望你们能够熟练掌握匿名内部类的使用技巧,充分发挥它的优势,让我们的编程之路更加顺畅。

225ca626797c46e2b3aaf27aa8dda7cf.jpeg

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/6765.html

(0)
LomuLomu
上一篇 2025 年 1 月 19 日 上午2:41
下一篇 2025 年 1 月 19 日 上午3:42

相关推荐

  • 【GreatSQL优化器-10】find_best_ref

    【GreatSQL优化器-10】find_best_ref 一、find_best_ref介绍 GreatSQL的优化器对于join的表需要根据行数和cost来确定最后哪张表先执行哪张表后执行,这里面就涉及到预估满足条件的表数据,在keyuse_array数组有值的情况下,会用find_best_ref函数来通过索引进行cost和rows的估计,并且会找出最…

    2025 年 1 月 15 日
    64000
  • Java刷题常见的集合类,各种函数的使用以及常见的类型转化等等

    目录 前言 集合类 ArrayList 1. 创建和初始化 ArrayList 2.添加元素 add 3.获取元素 get 4.删除元素 remove 5.检查元素 6.遍历 ArrayList LinkedList Stack 1. 创建Stack对象 2. 压入元素 (push) 3. 弹出元素 (pop) 4. 查看栈顶元素 (peek) 5. 检查栈…

    2025 年 1 月 1 日
    64300
  • 微软开源!Office 文档轻松转 Markdown!

    大家好,我是 Java陈序员。 今天,给大家介绍一款微软开源的文档转 Markdown 工具。 关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。 项目介绍 MarkItDown —— 微软开源的 Python 工具,能够将多种常见的文件格式(如 PDF、PowerPoint、Word、Excel、图像、音频…

    2025 年 1 月 15 日
    48500
  • NLP 中文拼写检测纠正论文-07-NLPTEA-2020中文语法错误诊断共享任务概述

    拼写纠正系列 NLP 中文拼写检测实现思路 NLP 中文拼写检测纠正算法整理 NLP 英文拼写算法,如果提升 100W 倍的性能? NLP 中文拼写检测纠正 Paper java 实现中英文拼写检查和错误纠正?可我只会写 CRUD 啊! 一个提升英文单词拼写检测性能 1000 倍的算法? 单词拼写纠正-03-leetcode edit-distance 72…

    未分类 2025 年 1 月 7 日
    30700
  • 【GreatSQL优化器-10】find_best_ref

    【GreatSQL优化器-10】find_best_ref 一、find_best_ref介绍 GreatSQL的优化器对于join的表需要根据行数和cost来确定最后哪张表先执行哪张表后执行,这里面就涉及到预估满足条件的表数据,在keyuse_array数组有值的情况下,会用find_best_ref函数来通过索引进行cost和rows的估计,并且会找出最…

    2025 年 1 月 12 日
    56400

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信