avatar

Java中的反射机制

什么是反射机制:

  • 编译期:编译器帮你把源代码翻译成机器能识别的代码,比如编译器把java代码编译成jvm识别的字节码文件
  • 运行期:将可执行文件交给操作系统去执行。
  • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

java的反射机制提供了什么功能?

  • 在运行时能够判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任一对象的方法
  • 在运行时创建新类对象

new和反射创建有什么区别

  • new: 静态编译,在编译期就将模块编译进来,执行该字节码文件,所有的模块都被加载;
  • 反射:动态编译,编译期没有加载,等到模块被调用时才加载;

Java反射是如何使用的

获取类–获取Class对象

  • 第一种方法:Class<?> classType = Class.forName() 可以通过传入一个全限定类名(包含包名)返回一个该类的Class类对象引用 。
try
{
Class a = Class.forName("mytest.testclass");//ClassPath:写需要反射的类名,一般是以包名.类名
System.out.println(a.getName());
}
catch (ClassNotFoundException e){
e.printStackTrace();
}
  • 第二种方法: Class<?> classType = object.getClass() 通过引用的到Class对象。这种方式主要是需要把类先实例化出来才能继续使用
testclass test = new testclass();//实例化
Class a = test.getClass();//对象的getClass方法实现
  • 第三种方法: Class<?> classType = Object.class 通过类字面常量获得,好处就是懒加载,只有使用时才会加载。
Class test = testclass.class;//直接使用类的.class方法,

第三种方法不需要进行异常捕获,上述两种方法搜需要进行异常处理

获得构造器

  • getDeclaredConstructors();    获取所有的构造函数
  • getDeclaredConstructor(参数类型);  获取一个所有的构造函数
  • getConstructors();          获取所有公开的构造函数
  • getConstructor(参数类型);        获取单个公开的构造函数

import java.lang.reflect.Constructor;

public class Main {
public static void main(String[] args) {
Class test = student.class;
Constructor[] constructors = test.getConstructors();//获取所有公开的构造函数
Constructor[] constructorsAll = test.getDeclaredConstructors();//获取所有的构造函数,包括私有的
try
{

Constructor constructorsSomeone= test.getConstructor(String.class);//获取指定参数的公开的构造函数
Constructor constructorsSomeoneAll = test.getDeclaredConstructor(String.class);//获取指定参数的所有构造函数
student obj = (student)constructorsSomeone.newInstance("哈哈");
obj.getname();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
class student
{
private student() {}//私有的构造函数
public student(String name)
{
System.out.println(name);
}
public student(String name,int a)
{
System.out.println(name);
}
public void getname()
{
System.out.println("呵呵");
}
}

获取修饰符

  • getModifiers();  //获取所有修饰符
    返回类型:整数类型,如果有两个修饰符,则返回两个修饰符之和,例如public static void getAll(){ }
    返回值会是public和static之和
    整数定义:
  • 0–默认不写
  • 1–public
  • 2–private
  • 4–protected
  • 8–static
  • 16–final
  • 32–synchronized
  • 64–volatile
  • 128–transient
  • 256–native
  • 512–interface
  • 1024–abstract
Class test = student.class;
Constructor[] constructors = test.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getModifiers());
}

获取后可以根据Modifier类进行判断

Constructor[] constructors = test.getDeclaredConstructors();
for (Constructor constructor : constructors) {
Modifier.isPublic(constructor.getModifiers());
}

获取名字

返回类型:String,可以反射类名,方法名,构造函数名等等
getName();    //获取全名 例如:com.bean.Book
getSimpleName()  //获取类名 例如:Book

Class test = student.class;
String name = test.getName();
String simplename = test.getSimpleName();

获得方法

  • getMethods()  //获取所有公开的方法
    注意:它会将系统自带的方法也得到
Class test = student.class;
Method[] methods = test.getMethods(); //获取所有的公开方法
for (Method method : methods) {
System.out.println(method.getName());
}
  • getDeclaredMethods()   //获取所有的方法
     注意:它不会获取系统自带的方法
Class test = student.class;
Method[] methods = test.getDeclaredMethods(); //获取所有的公开方法
for (Method method : methods) {
System.out.println(method.getName());
}
  • getDeclaredMethod(String name)    //获取单个的所有方法 参数是可指定方法名
Method method = test.getDeclaredMethod("getname");    //获取单个所有的方法
System.out.println(method.getName());
  • getDeclaredMethod方法可以重载为getDeclaredMethod (String name ,Class<?>… parameterTypes)
    可以获取该类的重载方法
Method method = test.getDeclaredMethod("getname",String.class);   
System.out.println(method.getName());

获取字段

  • getFields()   //获取所有的公开字段
  • getField(String name)  //参数可以指定字段  获取单个public字段
  • getDeclaredFields()  //获取所有的字段
  • getDeclaredField(String name)  //获取单个字段 参数可以指定字段
Class test = student.class;
try
{
//Public
Field[] fields = test.getFields(); //所有公开字段
Field id = test.getField("age"); //age字段
//所有
Field[] declaredFields = test.getDeclaredFields(); //所有字段
test.getDeclaredField("name"); //name字段
System.out.println(id.getName());
}
catch (Exception ex)
{
ex.printStackTrace();
}

获取修改字段相关信息

反射只是通过Class对象获得方法和字段,要获取实例的字段就要传入一个具体的实例。

获取字段值

1) Object value = field.get( Object obj) 通过get方法获得实例对象obj对应的field的值。

 try
{
student stu = new student("xxx");//创建实例
Field field = student.class.getField("name");
Object value = field.get(stu);//这样获取必须传入一个实例
}
catch (Exception ex)
{
ex.printStackTrace();
}

2) 如果field是静态字段则可以直接使用get(null)获取值。
3) 获取基本类型字段的值 : int value = field.get(Object obj) 获取int类型的字段。还有其他类型也是用同样的方法。
4) private修饰的字段无法直接获得,必须先设置file.setAccessible(true) 才能访问

获取字段相关信息并通过Modifier解析修饰符

  • Annotation<?> annotation = field.getAnnotation(Class annotationClass) 返回字段上的指定注解
  • Annotation[ ] annotations = field.getDeclaredAnnotations() 返回字段上的所有注解数组
  • Class<?> type = field.getType() 返回 字段 的类型 的 Class对象。
  • int modifier = field.getModifiers() 以int形式返回字段的修饰符。
    1) 通过Modifier静态方法判断是不是某一个权限修饰符,如Modifier.isPrivate(modifier)
    2) Modifier静态方法toString 返回权限标识符。

设置修改字段值

  • field.set( Object obj, Object value) 通过set方法设置实例对象obj对应的file字段的值为value。
  • 设置基本类型字段的值 :field.set(Object obj,int value) 获取int类型的字段。还有其他类型也是用同样的方法。
  • private修饰的字段无法直接设置,必须先设置field.setAccessible(true) 才能设置。
  • 被final修饰的字段,可以通过反射临时修改值,但是不会把原始值修改了,所以final是绝对不可变的。

获取包

返回类型:package
getPackage();

Package aPackage = test.getPackage();

获取接口

返回类型:Class[] interfaces
getInterfaces()

Class[] interfaces = test.getInterfaces();

获取父类/超类

返回类型:Class superclass
getSuperclass()

Class superclass = test.getSuperclass();

获取方法相关信息

和字段一样需要传入一个实例对象。

  • 获取字段相关信息并通过Modifier解析修饰符
    1) Annotation annotation = method.getAnnotation(Class annotationClass) 返回方法上的指定注解 2) Annotation[ ] annotations = method.getDeclaredAnnotations() 返回方法上的所有注解数组 3) Class type = field.getReturnType() 返回 方法返回值类型 的 Class对象。
    4) getModifiers()方法使用与获取字段的使用方式相同
  • 通过反射调用方法
    1) method.invoke(Object obj, Object… args) 传入实例对象obj和方法对应的参数。
    2) private修饰的方法无法反射,必须先设置method.setAccessible(true) 才能反射调用。

创建实例对象其他办法

  • 通过反射得来的构造器创建实例
Constructor<?> constructor = test.getConstructor(new Class[]{});
Student student1 = (Student)constructor.newInstance();
Constructor<?> constructor2 = test.getConstructor(new Class[]{int.class});
Student student2 = (Student)constructor2.newInstance(12);
  • 通过Class对象创建实例
Student student = Student.class.newInstance();
  • 还有通过 new 、 反序列化、colon( ) 方法创建对象,Java中所以一共有5种方法创建实例对象

参考链接:
JAVA 反射用法
java反射方法和使用

文章作者: zenshin
文章链接: https://zlh.giserhub.com/2020/03/04/cl35o0mr4003qp4tgcufz3vxk/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zenshin's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论