浅谈java中的反射机制

什么是反射机制?

Java反射机制是在运行过程中借助Reflection API,对于任意一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意一个方法,这种动态获取的信息以及动态调用对象的方法的功能成为java语言的反射机制。

 

java反射机制提供了那些功能?

  1. 在运行时判断任意一个对象所属的类;
  2. 在运行时构造任意一个类的对象;
  3. 在运行时判断任意一个类所具有的成员变量和方法;
  4. 在运行时调用任意一个对象的成员变量和方法;
  5. 生成动态代理。

那么也许就会有一些小朋友问:这个对象属于哪个类我直接看以下我写的代码不就知道了,为什么还要使用反射机制呢?那么接下来我举一个例子:

public class Demo {
	public Object object;
	public Demo(Object object){
		this.object = object;
	}
}

 在上面的例子中,我们通过构造参数给Demo类中的Object类型的属性进行了注入。调用Demo类的此构造方法的时候,就必须传入一个任意类型的对象进来。但是如果这个对象是外部传入的,并不知道它是什么类型的,那么这个时候我们就应该用到了反射。

跟反射相关的API:

  1. java.lang.Class: 反射的源头,要想使用java中的反射机制去完成一些事,那么必须要面对它。我们创建的类通过编译(javac.exe)之后会生成对应的.class文件,之后我们运行(java.exe)的时候JVM中的类加载器就会把.class文件加载至内存中。到了内存之后,.class文件就变成了一个运行时类被存储在缓存区中。而这个运行时类本身就是Class类的一个实例。 对于每一个类而言,JRE都为其保留一个不变的Class类型的对象(一个类在JVM中只会有一个Class的实例),其中包含了特定的某个类的相关信息,我们以后正是通过它来回去此对象所对应的类的信息。 又此过程可知,每一个类对应的Class类型的对象都是只能由系统建立。  只有有了Class实例之后才可以创建对应的运行时类的对象;获取对应的运行时类的完整结构(属性,方法,构造器,内部类,父类等信息);调用对应的运行时类的指定的结构。
  2. java.lang.reflect.Method(java.lang.reflect包中存储着与反射相关的类):提供关于类或者接口上单独某个方法以及如何访问该方法的信息。
  3. java.lang.reflect.Field:提供有关类或者接口的单个字段的信息以及它的动态访问权限。反射的字段可能是一个类的静态字段或者实例字段。
  4. java.lang.reflect.Constructor:提供关于类的单个构造方法的信息以及对它的访问权限。

获取运行时类的Class实例的方法:

     1.            调用运行时类本身的.class属性;

//得到Person类的Class类的实例 可以理解成clazz在栈中指向了运行时类Person
Class clazz = Person.class;

     2.            通过运行时类的对象的getClass( )获取;

Person person = new Person();
Class clazz = person.getClass();

     3.            通过Class类的静态方法forName( )获取;

Class clazz = Class.forName("com.demo.Person");//参数为运行时类的类路径

上面的1,2在编译器就会报错,但是3中如果路径写错的话那么只有在运行时才可以报错。

得到运行时类的对象:

//通过Class类的实例的到运行时类的对象
Person person = (Person)clazz.newInstance();

 Class类中与运行时类的属性相关方法:

     1.            getField("")得到运行时类或者其父类中使用public修饰的属性:

//获得Person类的属性名为name的属性
Field field = clazz.getField("name");//抛出NoSuchFieldException
//通过属性为运行时类的实例的相关属性进行赋值
//抛出IllegalArgumentException/IllegalAccessException
//第一个参数指明要操作的类的实例,第二个参数指明属性值
field.set(person,"张三");

     2.            getDeclaredFields("")获取运行时类全部的自身的属性(包括私有化属性)

Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
Field field = clazz.getDeclaredField("age");
//对私有化的属性进行操作setAccessible必须为true 默认为false
field.setAccessible(true);
field.set(person, 80);

      3.            getFields( )获取运行时类及其父类使用public修饰的全部属性

Class clazz = Person.class;
//获取运行时类被Public修饰的全部属性和其父类中声明为Public的属性
Field[] fields = clazz.getFields();
//遍历数组,并输出
for(Field f : fields){
	System.out.println(f);
}

 输出结果如下(Person类只有一个使用public修饰的name属性):

public java.lang.String po.Person.name

       4.            getDeclaredFields( )获取运行时类自身的全部属性

Field[] fields2 = clazz.getDeclaredFields();
for(int i = 0;i<fields2.length;i++){
	System.out.println(fields2[i]);
}

 输出结果如下:

public java.lang.String po.Person.name
private int po.Person.age

        5.           在Field[ ]中的到属性的修饰符:

Field[] fields3 = clazz.getDeclaredFields();
for(Field f  : fields3){
	//每一个权限修饰符对应一个int型数据 public-->1 private-->2 default-->0
	int i = f.getModifiers();
	//将Int型数据转换成权限修饰符
	String string = Modifier.toString(i);
	System.out.println(string);
}

  Class类中与运行时类的方法相关方法:

Class clazz = Person.class;
Method[] methods = clazz.getDeclaredMethods();
	//关于得到方法中的其他信息。具体看java.lang.reflect.Method API
	for(Method method:methods){
		System.out.println(method);
	}

 其输出结果如下:

public java.lang.String po.Person.toString()
public int po.Person.compareTo(java.lang.Object)
public java.lang.String po.Person.getName()
public void po.Person.setName(java.lang.String)
public void po.Person.setAge(int)
public void po.Person.show()
public int po.Person.getAge()
public void po.Person.display(java.lang.String) throws java.lang.Exception

   Class类中与运行时类的构造器相关方法:

Class clazz = Person.class;
Constructor[] constructors = clazz.getDeclaredConstructors();
    for(Constructor con : constructors){
		System.out.println(con.getName());
	}

 由上面的方法可以看出,其中的方法名都是大同小异:

  1. 由get开头,由Fields,Constructors或者Methods结尾,则表示得到运行时类及其父类的所有的使用public修饰的属性,构造器或者方法;
  2. 由get开头,由Field,Constructor或者Method结尾,就是得到运行时类及其父类的特定的使用public修饰的属性,构造器或者方法;
  • 由getDeclared开头,则具有得到运行时类的私有化属性的“权利”。

猜你喜欢

转载自blog.csdn.net/My_name_is_ZwZ/article/details/83796046