JAVA反射机制

16 篇文章 0 订阅
2 篇文章 0 订阅

1、什么是反射

能够分析类能力的程序称为反射(reflective )。 反射机制可以用来:

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

  1. 在运行时分析类的能力。
  2. 在运行时查看对象, 例如, 编写一个 toString 方法供所有类使用。
  3. 实现通用的数组操作代码。
  4. 利用 Method 对象, 这个对象很像中C++中的函数指针

1.1 获取字节码文件的方式

  1. 方式一:object类中的getClass方法,
    想要用这种方式,必须要明确具体的类,并创建对象。很麻烦

  2. 方式二:任何数据类型都具备应该静态属性 .class来获取对应的class文件
    相对简单,但还是要明确用到类中的静态成员,还是不够扩展

  3. 方式三: 只要通过给定的字符串名称就能获取该类,更为拓展。用class类中的forName方法完成

2、Class 类

在程序运行期间,Java 运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。 虚拟机利用运行时类型信息选择相应的方法执行。
然而,可以通过专门的 Java 类访问这些信息。保存这些信息的类被称为 Class, 这个名字很容易让人混淆。Object 类中的 getClass( ) 方法将会返回一个 Class 类型的实例。

Employee e;
Class cl = e.getClassO;

如同用一个 Employee 对象表示一个特定的雇员属性一样, 一个 Class 对象将表示一个特
定类的属性。最常用的 Class 方法是 getName。 这个方法将返回类的名字。例如,下面这条语句:

System.out.println(e.getClass().getName() + " " + e.getNameO);

如果 e 是一个雇员,则会打印输出:

Employee Harry Hacker

如果 e 是经理, 则会打印输出:

Manager Harry Hacker

我们还能通过调用静态方法forName来获取类名对应得class对象

这个方法只有在className是类名或者接口名得时候才能执行,否则forName方法将抛出一个checked_exception(已检查异常)。

2.1、newInstance()

我们可以使用newInstance(),动态创建一个类得实例

通过反射创建新的类示例,有两种方式:

一 、Class.newInstance() 

String s = "java.util .Random";
Object m = Cl ass.forName (s) .newlnstance();
或者
String s = "java.util .Random";
s.class.newInstance();

1.只能够调用无参的构造函数,即默认的构造函数; 
2.要求被调用的构造函数是可见的,也即必须是public类型的; 
3.抛出所有由被调用构造函数抛出的异常
二 、Constructor.newInstance() 

String s = "java.util .Random";
s.class.getConstructor().newInstance();

1.可以根据传入的参数,调用任意构造构造函数。
2.在特定的情况下,可以调用私有的构造函数。 

3、利用反射分析类的能力

在 java.lang.reflect 包中有三个类 Field、 Method 和 Constructor 分别用于描述类的字段(域)、 方法和构造器。 这三个类都有一个叫做 getName 的方法, 用来返回项目的名称。

  1. Field 类有一个 getType 方法, 用来返回描述域所属类型的 Class 对象。
  2. Method 和 Constructor 类有能够报告参数类型的方法
  3. Method 类还有一个可以报告返回类型的方法。这 三个类还有一个叫
    做 getModifiers 的方法, 它将返回一个整型数值,用不同的位开关描述 public 和 static 这样的修饰符使用状况
  4. 还可以利用java.lang.reflect包中的 Modifiei类的静态方法分析
    getModifiers 返回的整型数值。例如, 可以使用 Modifier 类中的 isPublic、 isPrivate 或 isFinal判断方法或构造器是否是 public、 private 或 final。 我们需要做的全部工作就是调用 Modifier类的相应方法,并对返回的整型数值进行分析,还可以利用 Modifier.toString方法将修饰符打印出来

3.1、Field

字段属性被对象调用,所有在设置对象属性的时候需要new 对象,
这里用反射的方式去new对象,然后再给字段赋值

Calss clazz= Class.forName("cn.itcats.bean.Person");
Field field = null 
//只能获取共有的
field = clazz.getField ("age") 
//只获取本类,但包含私有的
field = clazz.getDeclaredField ("age") 
// 对私有字段的访问取消权限检查,暴力访问
field.setAccessible(true);
Object obj = clazz.newInstance();
//给age赋值
field.set(obj ,18)//获取age的值
Object o = field.get(obj);

System.out.println(o)    //89

3.2、Method

获取方法:

Calss clazz= Class.forName("cn.itcats.bean.Person");
//获取的都是共有的方法,用数组接收
Method[] methods = clazz.getMethods();
//获取本类中的所有方法,包含私有的
methods = clazz.getDeclaredMethods();
// 遍历数组
for (Method method : methods  ){
	System.out.println(method );
}

运行方法:

Calss clazz= Class.forName("cn.itcats.bean.Person");
//show = 方法名 ,null  代表是空参数
Method method = clazz.getMethods(“show”, null);
//show = 方法名 ,后面 代表是有参数
Method method = clazz.getMethods(“show”, String.class ,int.class );

Constructor c = clazz.getConstructor(String.Class,int.Class);
Object obj = c.newInstance("小莫",37);
//既需要实体对象,又需要实例参数
method.invoke(obj, null)

4、反射方法的其他使用–通过反射越过泛型检查

泛型用在编译期,编译过后泛型擦除(消失掉),所以是可以通过反射越过泛型检查的

import java.lang.reflect.Method;
import java.util.ArrayList;
 
/*
 * 通过反射越过泛型检查
 * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
 */
public class Demo {
	public static void main(String[] args) throws Exception{
		ArrayList<String> strList = new ArrayList<>();
		strList.add("aaa");
		strList.add("bbb");
		
	//	strList.add(100);
		//获取ArrayList的Class对象,反向的调用add()方法,添加数据
		Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
		//获取add()方法
		Method m = listClass.getMethod("add", Object.class);
		//调用add()方法
		m.invoke(strList, 100);
		
		//遍历集合
		for(Object obj : strList){
			System.out.println(obj);
		}
	}
}

控制台输出:

aaa
bbb
100

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值