Java高级特性---反射机制

1、反射的原理是什么

一般情况下,如果想生成这个类的对象时,运行这个程序的JVM会确认这个类的Class对象是否已经加载,如果尚未加载,JVM就会根据类名查找.class文件,并将其载入,一旦这个类的Class对象被载入内存,它就可以被用来创建这个类的所有对象。
另外,对于一个未知类型的引用来说,通常会采用强制类型转换的形式来得到开发者想要的类型引用,如果只选了一个错误的类型转换,就会抛出一个ClassCastException异常。
在以上两个过程中,Class类一直都在起作用。因为Class类实例包含一个Java类的全部信息,包括类名、方法、属性等。Class对象就是代表一个类的类。
Java用Class类来代表了所有的类,方便了开发者掌控信息,通过Class,开发者可以得到属性(Field)、方法(Method)、构造器(Constructor)、修饰符(Modifier)等信息。在动态的获取这些信息以后,开发者就可以用该Class创建实例、调用任何方法、访问任何属性等操作,这些也是反射的主要用途。
反射机制相关的API主要集中在java.lang.reflect包下面,开发者也就是利用该包下面的接口和类进行相关的反射开发的。大多数的框架,如Struts、Hiberbate和Spring,都会频繁的使用反射API来完成他们的动态功能。

总结:
反射就是为了能够动态的加载一个类,动态的调用一个方法,动态地访问一个属性等动态要求设计的。它的出发点就在于JVM会为每个类创建一个java.lang.Class类的实例,通过该对象可以获取这个类的信息,然后通过使用java.lang.reflect包下的API已达到各种动态需求。

2、Class类的含义和作用

Class是用来记录类的各种信息的,伴随着类的加载而创建。一个普通的Java类会在一下几种情况,被加载到JVM中:

  1. 需要使用该类创建的对象。如下代码就会使Student类被加载到JVM中:
Student stu = new Student();
  1. 访问该类的静态成员;
System.out.println(Student.count);//访问静态的count成员变量
  1. 使用Class类的静态方法forName()方法,动态的加载一个指定类名的类,如果类没有找到,则抛出ClassNotFoundException异常:
Class.forName("com.test.Studeng");//动态加载Student类

JDBC导入驱动类,就是Class.forName()的一个常用例子。

类一旦被加载到JVM中,就会为它创建一个Class类的实例对象。要得到一个类的Class对象,可以通过以下几种途径。

  1. Class的forName()方法的返回值就是Class类型,也就是动态导入类的Class对象的引用。forName()方法的完整定义:
public static Class<?> forName(String className) throws ClassNotFoundEception
  1. 每个类都会有一个名称为Class的静态属性,通过它也可以获取Class对象的,
Class<Student> cla = Student.class;//访问Student类的class属性
  1. Object类中有一个名为getClass的成员方法,它返回的是对象运行时类的Class对象。因为Object类是所有类的父类,所以,所有的对象都可以使用该方法得到它运行时类的Class对象,
Student stu = new Student();
Class<Student> cla = stu.getClass();

获取到Class对象后,就可以通过调用它的一些成员方法来获取他所代表的类的属性、方法、修饰符等信息,以及调用newInstance()方法来创建新的实例对象。

总结
每一个Class类的对象就代表了一种被加载进入JVM的类,它代表了该类的一种信息映射。开发者可以通过一下3中途径获取到Class对象。

  1. Class类的forName()方法的返回值;
  2. 访问所有类都会拥有的静态的class属性;
  3. 调用所有对象都有的getClass()方法。

在Class类中,定义许多关于类信息的方法,例如getName()、getMethod()、getConstructor()、newInstance()等可以用于反射开发,还有isInstance()和isInterface()等一些关于类的功能方法。

3、如何操作类的成员变量(Field)

Field对象通过Class类的getDeclareField()或getDeclareFields()方法获取到,处于java.lang.reflect包。Field提供有关类或接口的单个字段的信息,以及对它的动态访问权限,反射的字段可能是一个静态的字段或实例的字段。
Field等方法主要分为两大类,getXXX和setXXX。其中getXXX是用于获取某个对象的该字段的值,并且有一定的类型规定,一般有两个参数,一个是对象引用,一个是需要设置的值。以下是一个Field的使用示例,通过反射比较两个对象的大小:

import java.lang.reflect.Field;

//测试类
class FieldTest{
	String name;
	int age;
	public FieldTest(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
}

public class TestField {
	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
		FieldTest obj1 = new FieldTest("hello1", 100);
		FieldTest obj2 = new FieldTest("hello2", 200);
		System.out.println(compare(obj1,obj2).name+"is bigger");
	}
	//用反射定义一个通用的比较方法,返回age相对更大的对象
	private static FieldTest compare(FieldTest obj1,FieldTest obj2) throws IllegalArgumentException, IllegalAccessException {
		
		try {
			Field field = obj1.getClass().getDeclaredField("age");
			field = FieldTest.class.getDeclaredField("age");
			int val1 = (Integer) field.get(obj1);
			int val2 = (Integer) field.get(obj2);
			if(val1 > val2) {
				return obj1;
			}else {
				return obj2;
			}
		} catch (NoSuchFieldException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return null;
	}
}

总结
Field提供有关类或接口的单个静态或实例字段的信息,它通过Class类的getDeclaredField()或getDeFields()方法获取到,再置于java.lang.reflect包下。Field的方法主要分为两大类,即getXXX和setXXX,都需要提供相应的实例对象,setXXX还需要提供设置的值。

4、如何操作类的方法(Method)

Method对象通过Class类的getMethod()或getMethods()方法获取到,也处于java.lang.reflect包下。Method提供关于类或接口中的某个方法的信息,所反映的方法可能是类方法或实例方法。
Method类中使用最多的是invoke(),通过它来完成方法被动态调用的目的。

5、如何利用反射实例化一个类

通常我们使用new关键字就可以实例化一个类,也就是创建一个对象。使用new关键字创建对象的时候,系统将调用类的某个构造方法。
根据调用构造方法的不同,用反射机制来实例化一个类,有两种途径。如果使用无参构造方法,则直接使用Class类的newInstance()方法即可;
若需要使用特定的构造方法来创建对象,则需要先获取Constructor实例,再用newInstance()方法创建对象。

6、如何利用反射机制来访问一个类的私有成员

在使用反射机制访问私有成员的时候,它们的可访问性是为false的。需要调用setAccessible(true)方法,把原本不可访问的私有成员变为可以访问以后,才能进行成功的访问或调用。

7、如何利用反射来覆盖数据对象的toString()方法

  1. 通过getDeclaredFields()方法得到所有的Field对象;
  2. 把上一步得到的Field对象数组进行遍历;
  3. 每一次循环加上字段名和字段值;
  4. 返回循环叠加以后的字符串结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值