Java语言访问修饰符(Access Modifiers)详解
在Java语言中,访问修饰符(Access Modifiers)用于控制类、接口、构造函数、方法和数据成员(字段)的可见性和访问级别。Java提供了四种主要的访问修饰符:
任何其他类都可以访问。适用于需要被广泛访问的类、方法或变量。
只有同一个包中的类和所有子类可以访问。适用于需要在继承关系享的成员。
如果没有指定访问修饰符,则默认为default(包私有)。
只有同一个包中的类可以访问。适用于只希望在同一包内可见的成员。
只有定义它的类可以访问。适用于只希望在类内部使用的成员。
- public:任何地方可见。
- protected:同一包和子类可见。
- default:同一包可见(没有修饰符时)。
- private:仅在类内部可见。
Java动态字节技术之Javassist
Javassist是一个开源的分析、编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码。相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。javassist简单易用, 快速。
重要的类
1. ClassPool:javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类,它的工作方式与 JVM 类装载器非常相似
2. CtClass: CtClass提供了类的操作,如在类中动态添加新字段、方法和构造函数、以及改变类、父类和接口的方法。
3. CtField:类的属性,通过它可以给类创建新的属性,还可以修改已有的属性的类型,访问修饰符等
4. CtMethod:类中的方法,通过它可以给类创建新的方法,还可以修改返回类型,访问修饰符等, 甚至还可以修改方法体内容代码
5. CtConstructor:与CtMethod类似
API运用
ClassPool
CtField
CtMethod
CtConstructor
1. 创建maven工程并添加依赖
添加依赖
添加Student类
2. 修改已有方法体,插入新的代码
对已有的student类中的sayHello方法,当调用时,控制台会输出: Hello, My name is 张三(name=张三)
需求:通过动态修改sayHello方法,当调用sayHello时,除了输出已经的内容外,再输出当前学生的age信息 创建JavassistDemo测试类,代码实现如下:
运行结果:
3. 动态添加方法
接下来我们给Student类添加一个计算的方法,但不是直接在Student类中添加,而是使用javassist,动态添加
控制台输出结果:
4. 动态创建类
下面我们再来个神的魔术,无中生有
运行结果:
javassist被用于struts2和hibernate中,都用来做动态字节码修改使用。一般开发中不会用到,但在封装框架时比 较有用。虽然javassist提供了一套简单易用的API,但如果用于平常的开发,会有如下几点不好的地方:
- 1. 所引用的类型,必须通过ClassPool获取后才可以使用
- 2. 代码块中所用到的引用类型,使用时必须写全量类名
- 3. 即使代码块内容写错了,它也不会像eclipse等开发工具一样有提示,它只有在运行时才报错
- 4. 动态修改的类,必须在修改之前,jvm中不存在这个类的实例对象。修改方法的实现必须在修改的类加载之前进行。
java基础之——访问修饰符(private/default/protected/public)
java中的访问修饰符包含了四种:private、default(没有对应的保留字)、protected和public。它们的含义如下:
- private:如果一个元素声明为private,那么只有同一个类下的元素才可以访问它。
- default:如果一个元素声明为default,那么只有同一个包下的元素才可以访问它。
- protected:如果一个元素声明为protected,那么只有同一个包下的元素或者子类中的元素才可以访问它。
- public:如果一个元素声明为public,那么所有位置(不管是否在同一个类中或同一个包下)的元素都可以访问它。
四种访问修饰符对元素的访问限制,由强到弱依次是private、default、protected和public。假如类A和类B的访问修饰符都是public,如果类A中的某个方法想要调用类B中的某个方法,那么可以根据下图确定可访问性:
如下举例说明四种修饰符对元素的访问限制:
类B中的方法想要调用同包下类A的private方法,编译时会报错:
private的一个典型使用场景是单例模式,将构造函数声明为private:
类C中的方法想要调用不同包下类A的default方法,编译时会报错:
类C中的方法想要调用类A的protected方法,编译时会报错:
无访问限制。
当子类中的方法隐藏/覆盖父类中的方法时,子类方法的访问修饰符与父类中对应方法的访问修饰符相比,访问限制应该相同或更弱。这是面向对象的基本原则,即子类应该是一个比父类更加完善的类,因此子类的可访问性应该更强。举例如下:
每个元素(例如类、接口、注解、构造函数、成员变量、成员方法等)都会显示或隐示的声明访问修饰符,但并不是每种元素都支持全部四种访问修饰符:
- 对于直接定义在包中的元素,例如类、枚举(本质就是继承了Enum的类)、接口、注解(本质就是继承了Annotation的接口),他们支持的访问修饰符是public和default。
- 对于定义在类内的元素,例如构造函数、成员变量、成员方法、内部类、内部接口等,他们支持全部四种访问修饰符。
- 对于定义在接口中的方法,只支持public(如果不指定,则会默认public);对于定义在接口中的变量,只支持public static final(如果不指定,则会默认public static final)。补充说明:接口中支持三种方法,即无消息体的方法(默认修饰符是public abstract)、通过default保留字定义的方法(默认修饰符是public)、通过static保留字定义的方法(默认修饰符是public)。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。