接口之美,内部之妙:深入解析Java的接口与内部类

简介: 接口之美,内部之妙:深入解析Java的接口与内部类

接口

接口不是类,而是对类的一组需求描述,这些类要遵从在接口中定义的统一格式。

接口中的所有方法自动地属于 public。因此,在接口中声明方法时,不必提供关键字 public。但是在方法的实现时,需要将方法根据需求进行作用域声明。

接口可以包含多个方法声明,Java8 以后可以在接口中添加默认方法。

接口中可以定义常量,但是不可以定义实例域(属性)。实例域和方法的实现应该由实现此接口的那个类来提供。

接口的特性

不能使用 new 进行实例化,不能创建接口对象,但是可以声明接口变量,接口变量必须引用实现了接口的类对象。

使用 instanceof 检查一个对象是否实现了某个接口,一个类可以实现多个接口。

接口可以使用 extends 进行继承

Java 的早期版本中,接口中不可以包含实例域和静态方法,后面 Java8 允许在接口中增加静态方法,但是这样做其实有些违背当初接口设计的初衷。之前想要为接口设计静态方法,通常是为接口设计一个伴随类,成对存在,比如:Collection/Collections。

接口中可以定义常量,接口中的常量默认为 public static final。有些接口专门只用来定义常量,那么所有实现此接口的类都自动的继承,可以直接使用而不需要使用类名.常量名的方式。

接口与抽象类

由于 Java 的单继承机制,一个类最多可继承自一个抽象类,但是可以实现多个接口。

相比 C++ 是支持多继承,但是多继承会让语言本身变得更加复杂,而且效率也会降低。那么接口可以提供多重继承的大多数好处,同时还能避免多重继承的复杂性和低效性。

接口的默认方法

Java8 后可以为接口方法提供一个默认的实现,需要使用 default 关键字标记。

声明了默认方法之后,类想要实现此接口就可以不一定重写此方法了。

默认方法的冲突问题
多个接口有相同的默认方法【手动解决】

父类(protected)和接口中有相同的方法【手动解决】

父类(public)和接口中有相同的方法【优先父类】

内部类

内部类式定义在另一个类中的类。

  1. 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
  2. 内部类可以对同一个包中的其他类隐藏起来。
  3. 当想要定义一个回调函数且不想编写大量代码时,使用匿名 (anonymous )内部类比较便捷。

内部类是一种编译器现象,与虚拟机无关。编译器将会把内部类翻译成用 $ (美元符号)分隔外部类名与内部类名的常规类文件,而虚拟机则对此一无所知。

例如:在 User 类内部的 Contact 类会被编译成类文件 User$Contact.class

使用内部类访问对象状态

内部类可以直接访问所在类的所有内容,比如私有的属性和方法。内部类的对象总有一个隐式引用,它指向了创建它的外部类对象。

内部类的分类

成员内部类

成员内部类:类比成员方法,不能拥有静态域但是可以访问外部类的静态域。

  • 成员内部类的创建需要依赖于外部类对象(成员方法必须通过对象调用),在没有外部类实例之前无法创建成员内部类对象。
  • 内部类与外部类相对独立,不是 is a 的关系。
  • 私有属性的互相访问,内部类可以直接访问外部类,而外部类访问内部类需要内部类的对象来访问。
  • 创建内部类的语法
  • 在外部类内部创建内部类对象 Inner inner = new Inner();
  • 在外部类外部创建内部类对象,外部类.内部类 inner = new Outter().new Inner();
  • 在内部类内部使用隐藏的外部类对象(隐藏的this),外部类名.this

静态内部类

定义在外部类的内部,使用static修饰,类比静态方法,静态内部类不需要外部类对象产生就能使用,不能访问外部类的成员域,但能访问静态域。

静态内部类的创建语法:

  • 外部类内部:Inner inner = new Inner();
  • 外部类外部:StaticInnerClass.Inner inner = new StaticInnerClass.Inner();

方法内部类/局部内部类

局部内部类不仅能够访问包含它们的外部类,还可以访问局部变量。不过,那些局部变量必须事实上为 final。这说明,它们一旦赋值就绝不

会改变。

局部类不能用 public 或 private 访问说明符进行声明。它的作用域被限定在声明这个局部类的块中。

局部类的优点是对外部世界完全隐藏。

匿名内部类

只创建这个类的一个对象,不需要明确定义类名。不过必须继承一个抽象类或者实现一个接口。而且匿名内部类是没有构造方法的。

内部类是否有用、必要和安全

代理

给一个对象提供一种代理对象以控制对该对象的访问。代理对象在不改变原对象代码的基础上对原对象的功能进行扩展。

使用代理降低了系统的耦合度,扩展性也会更好,还可以起到保护目标对象的作用。

代理模式在 Java 开发中是广泛应用的,特别是在框架中底层原理经常涉及到代理模式(尤其是动态代理)。

静态代理和动态代理,实际使用时还是动态代理使用的比较多。原因就是静态代理需要自行手写代码,维护、修改非常繁琐,会额外引入很多工作量。也不能很好的使用配置完成逻辑的指定,所以使用较少。

基于 JDK 和基于 CGLIB,实际使用时两个都会用到。

在 Spring 中,默认情况下它就支持了两种动态代理方式。如果你指定的目标类实现了接口,Spring 就会自动选择 JDK 的动态代理。而如果目标类没有实现接口,则 Spring 会使用 CGLIB。

我们在开发时,由于基于 JDK 的动态代理要求比较多,更不容易实现,所以很多人习惯于统一配置为使用 CGLIB 进行代理。也就是 CGLIB 更通用。

静态代理

静态代理维护复杂,一旦接口或父类发生改变,所有相关的类或接口就都得进行维护。

通过接口

让目标对象和代理对象都实现一个共同接口。那么这两个类就有了公共的方法,就可以在代理对象中实现对目标对象功能的扩展。

通过继承

让代理对象继承目标对象,那么代理对象就拥有目标对象的方法,同时又可以对其功能进行扩展。

动态代理

无需手写代理类,也不会存在代码编译的过程。运用在内存中生产代理类的技术在JVM的运行区造一个代理对象,只需对需要修改的部分进行编辑。

JDK 动态代理【接口】

CGLIB 动态代理【继承】

笔记大部分摘录自《Java核心技术卷I》,含有少数本人修改补充痕迹。

参考文章:http://gg.gg/12h2s6

相关文章
|
1月前
|
机器学习/深度学习 JSON Java
Java调用Python的5种实用方案:从简单到进阶的全场景解析
在机器学习与大数据融合背景下,Java与Python协同开发成为企业常见需求。本文通过真实案例解析5种主流调用方案,涵盖脚本调用到微服务架构,助力开发者根据业务场景选择最优方案,提升开发效率与系统性能。
464 0
|
1月前
|
Java
Java的CAS机制深度解析
CAS(Compare-And-Swap)是并发编程中的原子操作,用于实现多线程环境下的无锁数据同步。它通过比较内存值与预期值,决定是否更新值,从而避免锁的使用。CAS广泛应用于Java的原子类和并发包中,如AtomicInteger和ConcurrentHashMap,提升了并发性能。尽管CAS具有高性能、无死锁等优点,但也存在ABA问题、循环开销大及仅支持单变量原子操作等缺点。合理使用CAS,结合实际场景选择同步机制,能有效提升程序性能。
|
1月前
|
Java 开发者
Java并发编程:CountDownLatch实战解析
Java并发编程:CountDownLatch实战解析
369 100
|
15天前
|
存储 安全 Java
《数据之美》:Java集合框架全景解析
Java集合框架是数据管理的核心工具,涵盖List、Set、Map等体系,提供丰富接口与实现类,支持高效的数据操作与算法处理。
|
21天前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
162 0
|
1月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
84 11
|
1月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
13天前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
1月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
230 1
|
7月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
722 29

推荐镜像

更多
  • DNS
  • 下一篇
    开通oss服务