【Java】山外有山,类外还有类

【Java】山外有山,类外还有类

内部类是Java语言中的一种特性,它允许在另一个类中定义一个类。

内部类可以是静态的(不依赖于外部类的实例),也可以是非静态的(依赖于外部类的实例)。

在本篇博客中,我们将首先介绍内部类的使用特点,而后介绍几种内部类:

静态成员内部类

非静态成员内部类

局部内部类

匿名内部类

首先来看看内部类的使用特点:

image-20240505175218453

内部类的使用特点

  1. 访问控制:内部类可以直接访问外部类的成员,包括私有成员。
  2. 封装性:内部类可以隐藏在外部类中,对外不可见,增加了封装性。
  3. 继承:内部类可以继承外部类的属性和方法,也可以继承其他类或实现接口。
  4. 多态:内部类可以实现外部类不能实现的接口,实现多态。
  5. 生命周期:内部类的生命周期与创建它的外部类对象的生命周期相关联。
  6. 作用域:内部类的作用域限定在外部类中,只能在外部类中被访问。

什么时候使用内部类

当一个事物内部,还有一个部分需要完整的结构去描述,而这个内部的完整结构又仅为外部事物提供服务,则整个内部的完整结构,最好使用内部类。

例如:人类都有心脏,人类本身需要用属性去描述,人类内部的心脏,也需要特殊的属性和行为去描述,则心脏可以被定义成内部类,人类中的一个心脏类。

在实际的开发场景中,可能会有以下情形:

  1. 实现回调:使用匿名内部类来实现一个回调接口。
  2. 创建辅助类:创建一些仅供外部类使用的辅助类。
  3. 实现多态:通过内部类实现多态,特别是在设计模式中,如适配器模式、观察者模式等。

格式例如:

public class Outer {class Inner {// ...}
}

静态成员内部类

格式:直接在定义内部类的时候加上static关键字

public class A{static class B{}
}

注意:

  1. 内部类可以定义属性,方法,构造等
  2. 静态内部类可以被final或者abstract修饰,被final修饰之后,不能被继承,被abstract修饰之后,不能new
  3. 静态内部类,不能调用外部类的非静态成员
  4. 内部类还可以被四种权限修饰符修饰

调用静态内部类成员:

外部类.内部类 对象名 = new 外部类.内部类()

使用示例:

public class OuterClass {public static int staticField = 10;static class StaticInnerClass {void display() {System.out.println(staticField);}}public static void main(String[] args) {StaticInnerClass inner = new StaticInnerClass();inner.display();//或者OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();inner.display();}
}

非静态成员内部类

格式:

public class A{class B{}
}

调用非静态内部类成员:

外部类.内部类 对象名 = new 外部类().new 内部类()

使用示例:

public class OuterClass {private String outerField = "外部类字段";class NonStaticInnerClass {void display() {System.out.println(outerField);}}public void createInner() {NonStaticInnerClass inner = new NonStaticInnerClass();inner.display();}
}OuterClass outer = new OuterClass();
outer.createInner();
//或者
OuterClass.NonStaticInnerClass inner = new OuterClass().new NonStaticInnerClass();

局部内部类

局部内部类可以定义在方法中,代码块中,构造中。

例如:

  1. 辅助计算类
public class Calculator {public void calculate() {class Helper {int add(int a, int b) {return a + b;}}Helper helper = new Helper();int result = helper.add(5, 10);System.out.println("计算结果是: " + result);}
}
  1. 假如要完成临时任务
public class TaskRunner {public void runTask() {class Task {void execute() {System.out.println("执行临时任务");}}Task task = new Task();task.execute();}
}

内部类、接口、抽象类、普通类作方法参数

接口作为方法参数返回值,传递实参时,传递实现类对象。

接口作为返回值类型返回,实际返回的是实现类对象。

示例代码如下:

package com.hamburger.innerclass;public class main {public static void main(String[] args) {Mouse mouse = new Mouse();method(mouse);USB usb = method01();}/*接口作为方法参数,传递实参时,传递实现类对象*/public static void method(USB usb){usb.open();}public static USB method01(){Mouse mouse = new Mouse();return mouse;}
}
package com.hamburger.innerclass;public interface USB {public abstract void open();
}
package com.hamburger.innerclass;public class Mouse implements USB{public void open(){System.out.println("haha");}
}

抽象类

  1. 作为方法参数传递,传递实参时,传递的是其子类对象。
  2. 作为方法返回值类型返回,实际返回的是其子类对象。

普通类

  1. 作为方法参数传递,传递的是对象
  2. 作为方法返回值返回,返回的是对象

匿名内部类

匿名内部类,可以理解为没有显式声明出类名的内部类。它没有类名,通常用于创建一次性使用的类对象,特别是当需要快速实现某个接口或继承某个类时。

使用场景:我们如果想要实现接口,简单使用一次抽象方法,就需要:

创建一个实现类

实现这个接口

重写抽象方法

new实现类方法

如果我们只想单纯使用一次接口中的方法,能不能不要这么麻烦?

使用匿名内部类的方法:

  1. 创建实现类,实现接口
  2. 重写方法
  3. 创建实现类对象
  4. 调用方法

匿名内部类格式:

new 接口/抽象类(){重写方法
}.重写的方法();
===============================
类名 对象名 = new 接口/抽象类(){重写方法
}
对象名.重写的方法();

匿名内部类作为参数传递

package com.ham.niminginnerclass;
public class test {public static void main(String[] args){method(new USB() {@Overridepublic void open() {System.out.println("lzy");}@Overridepublic void close() {System.out.println("dyp");}}); }public static void method(USB usb){usb.open();usb.close();}
}package com.ham.niminginnerclass;public interface USB {public abstract void open();public abstract void close();
}

匿名内部类的使用场景:

  1. 事件监听器:在需要为事件添加监听器时,可以利用匿名内部类快速实现接口中的方法。
  2. 线程的实现:创建线程时,可以匿名内部类实现Runnable接口。
  3. 临时任务:当需要临时实现某个接口,且该实现不需要复用时。
  4. 回调函数:在需要提供回调函数时,可以使用匿名内部类快速实现。
  5. 实现策略模式:在实现策略模式时,可以使用匿名内部类来定义不同的策略。

使用示例

  1. 当需要创建一个线程来执行特定的任务时,可以使用匿名内部类实现Runnable接口:
// 使用匿名内部类创建线程
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程运行中");}
}).start();
  1. 在对对象数组进行排序时,可能需要提供一个自定义的比较器,这时可以使用匿名内部类:
// 使用匿名内部类实现比较器
String[] strings = {"banana", "apple", "orange"};
Arrays.sort(strings, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}
});
  1. 当需要临时实现一个接口,并且这个实现不需要在其他地方复用时,可以使用匿名内部类:
// 使用匿名内部类实现临时任务
public void performTask() {Task task = new Task() {@Overridepublic void execute() {System.out.println("执行临时任务");}};task.execute();
}

结语

参考文档如下:

【Java】内部类的使用方法和使用特点-CSDN博客

Java内部类详解(含:成员内部类、局部内部类、匿名内部类、静态内部类)-CSDN博客

36.内部类介绍_哔哩哔哩_bilibili

本篇作为复习内部类时的一部分笔记与总结,在之后仍会对本文不够详细之处作修订与补充。

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

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

相关文章

【时序大模型总结】学习记录(1)

1.TimeGPT-1 思路&#xff1a;在来自不同领域的大量数据上训练模型&#xff0c;然后对未见过的数据产生零样本的推断。 作者对TimeGPT进行了超过1000亿个数据点的训练&#xff0c;这些数据点都来自开源的时间序列数据。该数据集涵盖了广泛的领域&#xff0c;从金融、经济和天气…

C++进阶之路:深入理解编程范式,从面向过程到面向对象(类与对象_上篇)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

TypeScript学习日志-第十九天(namespace命名空间)

namespace命名空间 一、基本用法 namespace 所有的变量以及方法必须要导出才能访问&#xff0c;如图&#xff1a; 二、 嵌套 namespace 可以进行嵌套使用&#xff0c;如图&#xff1a; 它也必须需要导出才能访问 三、合并 当我们出现两个同名的 namespace 它就会合并这两…

【C++历练之路】STL中的哈希——手搓哈希底层逻辑

W...Y的主页 &#x1f495; 代码仓库分享 &#x1f60a; 前言&#xff1a; "hash"通常指的是哈希&#xff0c;它是一种将数据&#xff08;如字符串或者数字&#xff09;转换为一个固定长度的数值&#xff08;通常是整数&#xff09;的方法。哈希函数能够将任意长度…

C++笔试强训day15

目录 1.平方数 2.分组 Check函数的具体实现&#xff1a; 3.拓扑排序 1.平方数 链接 数学找规律&#xff0c;找离 x 最近的完全平方数 y。 先开平方根再利用四舍五入进位即可。 详细代码&#xff1a; #include <cmath> #include <iostream> using namespac…

读书笔记——《高质量C++/C编程指南》(2)

目录 前言 命名规则 共性规则 简单的Windows应用程序命名规则 表达式和基本语句 运算符优先级 复合表达式 if语句 布尔变量与零值比较 整型变量与零值比较 浮点变量与零值比较 指针变量与零值比较 对if 语句的补充说明 循环语句的效率 for 语句的循环控制变量 s…

第一天复习Qt文件读取

Qt文件操作&#xff1a; 1、QFile QTextStream操作文件案例&#xff1a; 1、打开文件 QFile file(absolute filepath | relative path); file.readLine()返回内容长度&#xff0c;如果为-1就是读取失败 file. Close()读取后关闭 file.errorString()返回文件打开发生的错误2、…

【算法】滑动窗口——将x减到0的最小操作数

本节博客主要是讲的我解“将x减到0的最小操作数”这道题的思路历程&#xff0c;从最开始的想法到代码提交的详细记录&#xff0c;有需要借鉴即可。 目录 1.题目2.代码示例3.细节3.1left越界3.2特殊情况 4.总结 1.题目 题目链接&#xff1a;LINK 看题目意思是就是给你一个数X&…

Java快速入门系列-11(项目实战与最佳实践)

第十一章&#xff1a;项目实战与最佳实践 11.1 项目规划与需求分析项目规划需求分析实例代码 11.2 系统设计考虑实例代码 11.3 代码实现与重构实例代码 11.4 性能优化与监控实例代码 11.5 部署与持续集成/持续部署(CI/CD)实例代码 11.1 项目规划与需求分析 在进行任何软件开发…

JavaScript异步编程——05-回调函数

我们在前面的文章《JavaScript 基础&#xff1a;异步编程/单线程和异步》中讲过&#xff0c;Javascript 是⼀⻔单线程语⾔。早期我们解决异步场景时&#xff0c;⼤部分情况都是通过回调函数来进⾏。 &#xff08;如果你还不了解单线程和异步的概念&#xff0c;可以先去回顾上一…

测试中Android与IOS分别关注的点

主要从本身系统的不同点、系统造成的不同点、和注意的测试点做总结 1、自身不同点 研发商&#xff1a;Adroid是google公司做的手机系统&#xff0c;IOS是苹果公司做的手机系统开源程度&#xff1a;Android是开源的&#xff0c;IOS是半开源的。所以IOS系统相对于Android来说是…

初探 Google 云原生的CICD - CloudBuild

大纲 Google Cloud Build 简介 Google Cloud Build&#xff08;谷歌云构建&#xff09;是谷歌云平台&#xff08;Google Cloud Platform&#xff0c;GCP&#xff09;提供的一项服务&#xff0c;可帮助开发人员以一致和自动化的方式构建、测试和部署应用程序或构件。它为构建和…