JAVA语言中的范围限制之可见范围与访问级别、泛型边界和密封类

简介: JAVA语言中的范围限制之可见范围与访问级别、泛型边界和密封类

写业务代码时间久了,编程语言本身的特征已经让我们渐渐忘记了,以JAVA语言为例,我们做J2EE开发,引用了大量的第三方框架或者类库,这些框架或者类库底层给我们提供了很多封装,让我们只需要按照他们提供的约定调用方法和增加配置即可以完成我们的业务功能。其实好的框架和类库底层做了大量的设计,使我们这些使用者在使用的时候不会对框架和库内部造成很多的影响或者威胁,如果没有做好这一点,就是有入侵的风险,也就是所谓的漏洞。为了做好这些工作,他们内部在设计的时候使用了大量的语言本身提供的机制或者技巧,也就是对数据或者类进行访问的范围限制。

虽然写业务代码很少使用很精细的范围控制,但是了解了这部分的知识有助于我们学习如何写一个优秀的框架或者类库。下面就从可见范围与访问级别泛型边界密封类三个方面去了解一下JAVA语言提供的范围限制。

可见范围与访问级别

在Java中,可见范围和访问级别是通过访问修饰符来控制的。访问修饰符定义了类、变量、方法和构造函数的访问级别,决定了它们在其他类或包中的可见性和可访问性。

Java提供了四种访问修饰符:

private(私有):被private修饰的成员只能在声明它们的同一类中访问。它们对于类的外部是隐藏的,无法在其他类中直接访问。私有成员只能通过类的公共接口(公共方法)间接访问。

默认访问级别(默认):如果没有显式指定访问修饰符,成员的访问级别就是默认的。默认访问级别适用于同一包内的其他类。在同一包内,可以直接访问默认访问级别的成员,而在不同包中是不可见的。

protected(受保护):被protected修饰的成员对于同一包内的其他类和继承关系中的子类是可见的。在同一包内,可以直接访问protected成员。在不同包中,可以访问继承了该类的子类的protected成员。

public(公共):被public修饰的成员对于所有类都是可见和可访问的。可以在任何地方直接访问public成员。

访问修饰符的选择取决于需要控制成员的可见性和访问级别。通常的原则是,将成员声明为最严格的可见范围,只暴露必要的接口(公共方法)来与类进行交互,从而提供更好的封装性和代码安全性。


泛型边界

泛型边界(Generic Bound)指定了可以作为泛型类型参数的类型范围。它允许在泛型类、接口或方法中对类型参数进行限制,以确保类型的一致性和兼容性。

泛型边界可以分为两种类型:上界边界(Upper Bound)和下界边界(Lower Bound)。

上界边界(Upper Bound):使用上界边界可以限制泛型类型参数为某个特定类或其子类。在声明泛型时,使用关键字 "extends" 后跟一个类或接口来指定上界边界。这意味着泛型类型参数必须是指定的类或其子类。

例如,假设有一个泛型类 Box<T>,可以使用以下方式指定上界边界:

class Box<T extends Number> {

   // 泛型类型参数 T 必须是 Number 类或其子类

}

在这个例子中,T 可以是 Integer、Double 或其他继承自 Number 类的类型。

下界边界(Lower Bound):使用下界边界可以限制泛型类型参数为某个特定类或其父类。在声明泛型时,使用关键字 "super" 后跟一个类来指定下界边界。这意味着泛型类型参数必须是指定的类或其父类。

例如,假设有一个泛型类 Box<T>,可以使用以下方式指定下界边界:

class Box<T super Number> {

   // 泛型类型参数 T 必须是 Number 类或其父类

}

在这个例子中,T 可以是 Number、Object 或其他 Number 的父类。

通过使用泛型边界,可以在编写泛型类、接口或方法时增加类型的限制,从而提高代码的安全性和可靠性。


密封类

在JDK 17中,引入了密封类(Sealed Classes)的功能。密封类是一种限制类继承关系的机制,可以控制哪些类可以扩展或实现密封类。

使用密封类可以在类的继承层级中明确指定允许继承的子类,从而增强了代码的可维护性和安全性。

要声明一个密封类,需要在类的声明上使用 sealed 关键字。然后,可以使用 permits 关键字列出允许继承的类。只有列出的类才能继承密封类。

以下是一个使用密封类的示例:

sealed class Shape permits Circle, Rectangle, Triangle {

   // 密封类的定义

 

   // 可以在密封类内部定义一些通用的方法和属性

}

final class Circle extends Shape {

   // Circle 继承自 Shape,是允许的

   // 可以添加 Circle 特定的方法和属性

}

non-sealed class Rectangle extends Shape {

   // Rectangle 继承自 Shape,是允许的

   // 因为 Rectangle 不是密封类,所以其他类也可以继承它

}

final class Triangle extends Shape {

   // Triangle 继承自 Shape,是允许的

   // 可以添加 Triangle 特定的方法和属性

}

class Square extends Rectangle {

   // Square 继承自 Rectangle,但 Rectangle 不是允许继承的类

   // 所以这个继承是不允许的,会在编译时报错

}


总结

本文将可见范围与访问级别、泛型边界和密封类三个概念放在一起做一个介绍和比较,并没有涵盖JAVA语言所有的范围限制的概念,只是随笔想到这三个概念跟我们对数据或者类的控制有关系,所以才凑在一起,供大家参考和自己学习。其实设计一个良好的类库对外提供服务,需要很缜密的设计和科学规范的约束,虽然上述三个概念独立开来不是那么复杂,但是要是综合使用到我们的代码中,尤其是交叉几个在一起(如果代码设计需要的话),还是相当复杂的,这些都是我们平时写CURD,写MVC架构的业务代码很少接触的技巧。


目录
相关文章
|
12天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
36 17
|
6天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
18 4
|
4天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
8天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
41 4
|
9天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
20 2
|
13天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
14天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
30 3
|
3月前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
58 7
|
20天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
15 3
|
20天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
27 2