写业务代码时间久了,编程语言本身的特征已经让我们渐渐忘记了,以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架构的业务代码很少接触的技巧。