您的位置:首页 > 编程语言 > Java开发

JAVA中的反射机制

2016-05-25 17:53 363 查看
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。


先看一下反射的概念:

              主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

             反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

             看概念很晕的,继续往下看。

 


反射机制的作用:

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

在这里先看一下sun为我们提供了那些反射机制中的类:

java.lang.Class;                

java.lang.reflect.Constructor; java.lang.reflect.Field;        

java.lang.reflect.Method;

java.lang.reflect.Modifier;

class 类

众所周知Java有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中getClass()返回一个Class 对象。Class
类十分特殊。它和一般类一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被加载,或当加载器(class
loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。如果您想借由“修改Java标准库源码”来观察Class 对象的实际生成时机(例如在Class的constructor内添加一个println()),这样是行不通的!因为Class并没有public constructor。

具体实现

使用java的反射机制,一般需要遵循三步:

获得你想操作类的Class对象
通过第一步获得的Class对象去取得操作类的方法或是属性名
操作第二步取得的方法或是属性

     Java运行的时候,某个类无论生成多少个对象,他们都会对应同一个Class对象,它表示正在运行程序中的类和接口。如何取得操作类的Class对象,常用的有三种方式:

调用Class的静态方法forName,如上例;
使用类的.class语法,如:Class<?> cls = String.class;
调用对象的getClass方法,如:String str = "abc";Class<?> cls = str .getClass();

首先我们写一个Employee类
public class Employee {
public Employee(){
name = "nick";
age = 25;
}
String name="";
int age=0;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


1,反射机制获取类有三种方法,我们来获取Employee的Class类
//第一种方式:
Class c1 = Class.forName("package.xxx.Employee"); //完整的路径名
//第二种方式:
//java中每个类型都有class 属性.
Class c2 = Employee.class;

//第三种方式:
//java语言中任何一个java对象都有getClass 方法
Employee e = new Employee();
Class c3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
注意 Employee若是内部类,这类名前为$号,而不是“.”
 

2,创建对象:获取类以后我们来创建它的对象,利用newInstance:

Class c =Class.forName("com.jd.wxsq.jzcircle.bean.Employee");
//创建此Class 对象所表示的类的一个新实例
Object o = c.newInstance(); //调用了Employee的无参数构造方法.




注意,若获取内部类构造方法时,需要将其外部类的类对象作为参数传进去

Constructor constructor = c.getDeclaredConstructor(new Class[] {

Out.class });

同样实例化内部类时,也需要将外部类对象作为参数传进去

obj = constructor.newInstance(new Out());

    3,获取属性:分为所有的属性和指定的属性:
//获取所有的属性?
Field[] fs = c.getDeclaredFields();
//定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
//通过追加的方法,将每个属性拼接到此字符串中
//最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
//里边的每一个属性
for(Field field:fs){
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
sb.append(field.getName()+";\n");//属性的名字+回车
}

sb.append("}");
由打印信息我们可以看到能够获取到Employee的所以成员。

//获取特定的“name"属性
Field f = c.getDeclaredField("name");
//使用反射机制可以打破封装性,导致了java对象的属性不安全,设置可访问
f.setAccessible(true);
//给o对象的name属性赋值
f.set(o,"Join");
通过上面方法我们可以获取指定的属性,并改变它的值。

4,获取方法

//获取特定的setAge方法,Integer.TYPE为其对应的形参数类型
Method method = c.getDeclaredMethod("setAge",Integer.TYPE);
//调用特定的setAge方法,若为静态方法,则invoke的第一个参数为null
method.invoke(o,100);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: