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

点赞 0
收藏 0

文章为作者独立观点不代本网立场,未经允许不得转载。