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架构的业务代码很少接触的技巧。


目录
相关文章
|
4月前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
426 5
|
4月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
364 18
|
4月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
197 4
|
4月前
|
IDE JavaScript Java
在Java 11中,如何处理被弃用的类或接口?
在Java 11中,如何处理被弃用的类或接口?
272 5
|
4月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
260 1
|
4月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
321 1
|
Java API 容器
Java泛型的继承和通配符
Java泛型的继承和通配符
124 1
|
安全 Java API
Java一分钟之-泛型通配符:上限与下限野蛮类型
【5月更文挑战第19天】Java中的泛型通配符用于增强方法参数和变量的灵活性。通配符上限`? extends T`允许读取`T`或其子类型的列表,而通配符下限`? super T`允许向`T`或其父类型的列表写入。野蛮类型不指定泛型,可能引发运行时异常。注意,不能创建泛型通配符实例,也无法同时指定上下限。理解和适度使用这些概念能提升代码的通用性和安全性,但也需兼顾可读性。
363 3
|
Java 编译器
[java进阶]——泛型类、泛型方法、泛型接口、泛型的通配符
[java进阶]——泛型类、泛型方法、泛型接口、泛型的通配符
195 0
|
Java Go
【Java 泛型方法】泛型方法的定义和使用,泛型的通配符和泛型的上下限,泛型的注意事项
【Java 泛型方法】泛型方法的定义和使用,泛型的通配符和泛型的上下限,泛型的注意事项
151 0