Java反射常见使用方法

动态语言

动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。比如常见的JavaScript 就是动态语言,除此之外Ruby,Python 等也属于动态语言,而C、C++则不属于动态语言。从反射角度说JAVA 属于半动态语言。

引入反射的目的

关于java语言中为什么要引入反射,有以下3个原因:

  1. 提高编程的灵活性,java代码在执行时,需要知道这个类的所有属性及方法,增加注解,事务回滚,反射就可以解决。
  2. 赋予jvm动态编译的能力,例如热加载,Tomcat的classLoader。

反射机制概念

  1. 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。
  2. 反射可以在一个类运行的时候获取类的信息的机制,可以获取在编译期不可能获得的类的信息。
  3. 对于任意一个对象,都能调用它的任意一个方法和属性。
  4. 因为类的信息是保存在Class对象中的,而这个Class对象是在程序运行时被类加载器(ClassLoader)动态加载的。
  5. 当类加载器装载运行了类后,动态获取Class对象的信息以及动态操作Class对象的属性和方法的功能称为Java语音的反射机制。

反射的应用场景

编译时类型和运行时类型

在Java 程序中许多对象在运行是都会出现两种类型:编译时类型和运行时类型。 编译时的类型由声明对象时实用的类型来决定,运行时的类型由实际赋值给对象的类型决定 。如:

Person p = new Student();

其中编译时类型为Person,运行时类型为Student。

某些从外部传入的对象,在编译期时类型为Object,但是在运行时,需要获取该对象和类的真实信息,比如获取该类的某个方法。因为编译时无法预知该对象和类属于哪个类,程序只能依靠运行时信息来预测该对象和类的真实信息,此时就必须使用反射了。

Java 反射API

通过Java反射可以获取JVM中的类、接口或对象的信息。

Class —— 类的创建

1. 获取Class对象的方法
// 会让ClassLoader装载类,并进行 
Class c1 = Class.forName("com.mxm.Reflect");

// 返回类对象运行时真正所指的对象、所属类型 
Class c2 = Reflect.class;

// ClassLoader装载入内存,不对类
Class c3 = new Reflect().getClass();
  1. 无参数创建对象
//newInstance式使用类的加载机制 
Class c4 = Class.forName("com.mxm.Reflect");Object o = c4.newInstance();
  1. 有参数创建对象
// Class对象所表示的类的指定的公共构造 , getConstructor方法返回了一个Constructor对象,它反映了此
Constructor<?> csr = c4.getConstructor(String.class,,int.class);
Object o = csr.newInstance("王",28);

Constructor —— 反射类中构造方法

Field —— 反射方法

  1. 获取属性
Field field = class.getDeclaredField("name");使用setAccseeible取消封装,特别是可以取消私有字段的访问权限。field.setAccessible(true);
field.set(object,"老王");
  1. Field类描述

Field类描述的是属性对象,其中可以获取到很多属性信息,包括名字、属性类型、属性的注解。Java.lang.reflect包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。

  1. 安全管理

在安全管理器中会使用checkPermission方法来检查权限 ,而setAccessible(true)并不是将方法的权限改为public,而是取消Java的权限控制检查,所以即使是public方法,其accessible属性默认也是false,就是说也要做权限检查的。

  1. 修改属性中的修饰符
Field field = class.getDeclaredField("name");
String prive = Modeifier.toString(field.getModofoers());

Method —— 反射方法

Method m = class.getDeclaredMethod("setName",String.class);
m.setAccessible(true); //同样需要忽略访问权限的限制
m.invoke(class,"老王");

Modifier —— 访问修饰符的信息

反射使用步骤(获取Class 对象,调用对象方法)

  1. 获取想要操作的类的Class 对象,他是反射的核心,通过Class 对象我们可以任意调用类的方法。
  2. 调用Class 类中的方法,既就是反射的使用阶段。
  3. 使用反射API 来操作这些信息。

获取Class 对象的3 种方法

  1. 调用某个对象的getClass()方法。
Person p=new Person();
Class clazz=p.getClass();
  1. 调用某个类的class属性来获取该类对应的Class对象
Class clazz=Person.class;
  1. 使用Class类中的forName()静态方法(最安全/性能最好)
Class clazz=Class.forName("类的全路径"); (最常用)

当我们获得了想要操作的类的Class 对象后,可以通过Class 类中的方法获取并查看该类中的方法和属性。

//获取Person 类的Class 对象
Class clazz=Class.forName("reflection.Person");
//获取Person 类的所有方法信息
Method[] method=clazz.getDeclaredMethods();
for(Method m:method) {
   System.out.println(m.toString());
}
//获取Person 类的所有成员属性信息
Field[] field=clazz.getDeclaredFields();
for(Field f:field) {
  System.out.println(f.toString());
}
//获取Person 类的所有构造方法信息
Constructor[] constructor=clazz.getDeclaredConstructors();
for(Constructor c:constructor) {
   System.out.println(c.toString());
}

反射实践

  1. 获取不到Class。当Class.foeName()中路径获取不到对应的Class时,会抛出异常。
  2. 获取不到Field。(1)确实不存在这个Field,抛出异常。(2)修饰符导致的权限问题,抛出相同异常。
  3. 获取父类修饰符。
    (1)getField只能获取对象和父类的public修饰的属性。
    (2)getDeclaredField获取对象中的各种修饰符属性,但是不能获取父类的任何属性。
    (3)先使用getSupperclass方法可以获取父类的suppereClass对象,再使用getDeclaredField方法获取父类的全部属性。
  4. 获取不到父类的非public的方法
  5. 获取不到父类的构造方法
  6. 反射静态方法
    static方法因为属于类本身 , 关键是Method.invoke的第一个 , 所以不需要填写对象,填写null就可以
public class TestMethod {       
static void test(){}
}
Class cla = Class.foeName("TestMethod");
Method m = cla.getDeclaredMethod("test");
m.invoke(null);
  1. 反射泛型参数方法
    (1)Java的泛型擦除概念,泛型T在编译时会自动向上转型为Object。
public class Test<T> {      
public void test(T t){}
}  
Class cla = Test.class;
Method m = cla.getDeclaredMethod("test",Object.class);
m.invoke(new Test<Integer>(),1);
  1. 反射框架:jOOR

newInstance方法创建类对象的两种方法

Class 对象的newInstance()

  1. 使用Class 对象的newInstance()方法来创建该Class 对象对应类的实例,但是这种方法要求该Class 对象对应的类有默认的空构造器。

调用Constructor对象的newInstance()

  1. 先使用Class 对象获取指定的Constructor 对象,再调用Constructor 对象的newInstance()方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例。
//获取Person 类的Class 对象
Class clazz=Class.forName("reflection.Person");
//使用.newInstane 方法创建对象
Person p=(Person) clazz.newInstance();
//获取构造方法并创建对象
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
//创建对象并设置属性
Person p1=(Person) c.newInstance("李四","男",20);
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值