Java高级基础——反射(Reflect)

一、Class类

在Java中,所有的类都是java.lang.Class的实例对象,而java.lang.Class只能由JVM进行实例。当每一个类被装入JVM时,它将自动创建与之相关联的Class类对象。
下列代码演示了三种获取Class类对象(Class Type)的方式,以及两种获取Person类对象的方法:

try {
	// 利用Person类,实例化一个Person类对象p1
	Person p1 = new Person();
	// 利用Person类的静态成员class,实例化一个Class类对象c1
	Class c1 = Person.class;
	// 利用Person类对象p1的方法getClass(),实例化一个Class类对象c2
	Class c2 = p1.getClass();
	// 利用Class类的forName()方法,实例化一个Class类对象c3
	Class c3 = Class.forName("myself.Person");
	// 利用Class类对象c1,实例化了一个Person类对象person2
	Person person2 = (Person) c1.newInstance();
} catch (Exception e) {
	e.printStackTrace();
}

c1、c2、c3都引用了Person类的Class Type,所以c1 == c2 == c3
而p1和p2分别引用了两个Person类实例,所以p1 != p2


二、动态加载类

传统的new创建对象的方式需要在编译时完成,如果未来新增了类,则需要对整个代码进行修改并重新编译,我们可以利用反射的知识进行运行时动态加载类。
由于此处无法演示运行时的情景,下面的代码将以工厂方法的方式类比说明:

package reflect;

/**
 * Person工厂类对象
 *
 */
public class PersonFactory {

	/**
	 * 静态方法:动态创建Person类对象
	 * 
	 * @param name 类的完整路径
	 * @return 类对象
	 */
	public static Person createPerson(String name) {
		Person person = null;
		try {
			person = (Person) Class.forName(name).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return person;
	}

	public static void main(String[] args) {
		PersonFactory.createPerson("reflect.Teacher").say(); // 成功执行Teacher的say方法
		PersonFactory.createPerson("reflect.Student").say(); // 成功执行Student的say方法
	}

}

上述代码中,Teacher类和Student类都是Person接口的实现类,如果按照传统的方式,Teacher类的创建需要一个工厂方法(new Teacher()),Student类的创建也需要一个工厂方法(new Student()),如果将来还有更多的Person实现类,那么每一个类都需要实现一个工厂方法,十分冗长和低效。
我们希望通过同一个工厂方法选择性的去生成类对象,这时反射就可以派上用场了。用户可以自行传入类全名,工厂方法会先创建其Class对象,接着会根据Class对象实例出Person类对象,最后将该对象返回。如此一来,一个工厂方法就能够动态创建Person接口下的所有实现类了。


三、获取方法的信息

// 获取类的Class类型
Class c = obj.getClass();
// 获取类的所有public方法
Method[] ms1 = c.getMethods();
// 获取类自身的所有方法
Method[] ms2 = c.getDeclaredMethods();
for (int i = 0; i < ms.length; i++) {
	// 获取方法返回值类型的Class类型
	Class returnType = ms[i].getReturnType();
	// 获取方法参数列表类型的Class类型
	Class[] paramTypes = ms[i].getParameterTypes();
}

四、获取成员变量的信息

// 获取类的Class类型
Class c = obj.getClass();
// 获取类的public成员变量
Field[] fs1 = c.getFields();
// 获取类的自身的所有成员变量
Field[] fs2 = c.getDeclaredFields();
for (Field field : fs) {
	// 获取成员变量类型的Class类型
	Class fieldType = field.getType();
}

五、获取构造函数的信息

// 获取类的Class类型
Class c = obj.getClass();
// 获取类的public构造函数
Constructor[] cs1 = c.getConstructors();
// 获取类所有的构造函数
Constructor[] cs2 = c.getConstructors();
for (Constructor constructor : cs) {
	// 获得构造函数参数列表的Class类型
	Class[] paramTypes = constructor.getParameterTypes();
}

六、方法的反射

public class Person {
	
	public void say() {
		System.out.println("你好呀!");
	}
	
	public void say(String a) {
		System.out.println("你好呀!" + a);
	}
	
	public void say(String a, String b) {
		System.out.println("你好呀!" + a + "和" + b);
	}

}


public class Test {

	public static void main(String[] args) {
		try {
			// 实例化一个Person类对象p
			Person p = new Person();
			// 获取p对象的Class类型
			Class c = p.getClass();
			// 从类的所有public方法中,获取对应的方法
			Method m = c.getMethod("say", String.class);
			// 从类自己的方法中,获取对应的方法
			Method m2 = c.getDeclaredMethod("say", String.class, String.class);
			Object o = m.invoke(p, "小红");
			Object o2 = m2.invoke(p, "小红", "小明");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

七、泛型与反射

Java中的泛型是编译时用于匹配类型的技术,而反射是绕过编译而进行的操作,所以Java中的泛型在反射操作中是无效的。

try {
	List<String> list = new ArrayList<String>();
	list.add("小红");
	Class c = list.getClass();
	Method m = c.getMethod("add", Object.class);
	m.invoke(list, "250"); // 添加整形成功,说明泛型失效
	System.out.println(list); // 打印[小红, 250]
} catch (Exception e) {
	e.printStackTrace();
}
发布了48 篇原创文章 · 获赞 4 · 访问量 6150

猜你喜欢

转载自blog.csdn.net/Knightletter/article/details/103457842