本篇文章给大家带来的内容是关于浅析Java内部类的各种用法(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
内部类(inner class)是定义在另一个类内部的类。之所以定义在内部是因为内部类有一些普通类没有的“特权”,可以方便实现一些需求。
内部类
先来看一个简单的例子:
public class Apple { private int size = 16; private class Book { public void print() { System.out.println(size); } } }
Book类就是定义在Apple类中的一个内部类,Book类引用了Apple类的私有域size却没有报错,这就是上文提到的特权了,内部类可以引用外围类的所有域和方法包括私有的。那么为什么内部类可以做到这样神奇的事情呢?原来是编译器在背后偷偷干的好事!
把上文的例子编译后可以看到编译器会额外生成一个Apple$Book.class文件:
class Apple$Book { private Apple$Book(Apple var1) { this.this$0 = var1; } public void print() { System.out.println(Apple.access$000(this.this$0)); } }
可以看到这个类的名称是用外围类名称加内部类名称用$符号分割,而且编译器在内部类的构造函数里自动添加了一个外围类的参数,这样内部类就能引用到外围类的域和参数了。
不过这样还有一个问题,我们完全可以按普通的方式自己写一个构建方式来接收Apple类而不用内部类的方式,不过这样的类却无法引用Apple类的私有域和私有方法。
眼尖的同学可能已经发现奥秘了,Apple.access$000(this.this$0)这一条语句就是关键了。内部类在引用外围类的私有域和方法时编译器会在外围类内部生成一个静态方法access$XXX,这个方法会返回外围类的私有域或调用私有方法,方法的第一个参数是外围类的引用。
不过这样就有了安全风险,任何人都可以通过调用Apple.access$000方法很容易地读取到私有域size。当然,access$000不是Java的合法方法名。但熟悉类文件结构的黑客可以使用十六进制编辑器轻松地创建一个用虚拟机指令调用那个方法的类文件。由于隐秘地访问方法需要拥有包可见性,所以攻击代码需要与被攻击类放在同一个包中。
特殊的语法
内部类有一些特殊的语法,比如获取传入的外围类引用的语法是OuterClass.this,外围类的类名加上this关键字。还有明确的使用内部类的构建函数outerObject.new InnerClass {construction parameters)。在内部类中声明的静态域必须是不可变的,即必须用final修饰符修饰,且不能有静态方法。例子:
public class Apple { private int size = 16; private class Book { public void print() { System.out.println(Apple.this.size); } } public static void main(String[] args) { Apple apple = new Apple(); Apple.Book book = apple.new Book(); } }
局部内部类
内部类也可以在一个方法内声明,这样定义的内部类就是局部内部类。局部内部类和内部类的区别在于局部内部类的作用域局限于定义它的方法块内,除了这个方法内部局部内部类都是不可见的。
public class Apple { private int size = 16; private void print() { class Book { public void print() { System.out.println(size); } } Book book = new Book(); book.print(); } }
匿名内部类
顾名思义,匿名内部类是一种没有类名的类。因为有时候我们只需要有一个一次性使用的类的对象,匿名内部类可以方便我们实现。通常的语法格式为:
SuperType superType = new SuperType(construction parameters) { inner class methods and data }
如果SuperType是一个接口,那么就需要在大括号里实现接口定义的抽象方法。如果SuperType是一个类,可以在大括号里扩展这个类。因为匿名内部类没有类名,所以是不能定义构建函数的。在Java8以后,使用lambda表达式会比匿名内部类更加方便。
双括号初始化
利用匿名内部类的特殊语法的特殊初始化技巧,比如初始化一个数组:
List<String> arrayList = new ArrayList<String>() {{ add("test"); add("test2"); }};
不过就这个例子来说这样更好:List
静态内部类
上文说到内部类都会有一个外围类的引用,不过有时我们只是想把类放在另一个类内部并不需要引用它,这时就可以用到静态内部类。例子:
public class Apple { private int size; private int price; public Apple(int size, int price) { this.size = size; this.price = price; } public static void main(String[] args) { Apple apple = AppleBuilder.builder().setPrice(20).setSize(16).build(); } static class AppleBuilder { private int size; private int price; static AppleBuilder builder() { return new AppleBuilder(); } Apple build() { return new Apple(size, price); } AppleBuilder setSize(int size) { this.size = size; return this; } AppleBuilder setPrice(int price) { this.price = price; return this; } } }
以上是浅析Java内部类的各种用法(代码示例)的详细内容。更多信息请关注PHP中文网其他相关文章!

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

Dreamweaver CS6
视觉化网页开发工具

禅工作室 13.0.1
功能强大的PHP集成开发环境

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。