Java学习系列(二十)Java面向对象之反射详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45289391

前言

今天讲讲Java中的反射。我们常见的反射多用于JDBC中的加载驱动程序Class.forName("com.mysql.jdbc.Driver");、Struts的MVC、Hibernate中的ORM、Spring中的IOC还有一些其他框架等等。那它有什么好处呢?它的好处就是能够动态的创建对象和编译且能够访问某个类中的所有(包括私有)属性方法及对象的属性方法并进行调用,比较灵活,这样也有利于降低类间的耦合度;但反射也有缺点,就是破坏了类的封装性和对象的完整性。

实例说明

/**
 * 目标类
 * 
 * @author [*昨日重现*] [email protected]
 * @since version 1.0
 * @datetime 2015年4月26日 下午4:50:28
 */

public class Student {
	private String name;
	private Integer age;

	/**
	 * 无参构造并赋默认值
	 */
	public Student() {
		this.name = "张三";
		this.age = 22;
	}

	public Student(String name, Integer age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

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

	public Integer getAge() {
		return age;
	}

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

	public void info() {
		System.out.println("做一个快乐的程序员~" + this);
	}

	private void joke() {
		System.out.println("开个玩笑啦。。。");
	}

	// 无参
	public void play() {
		System.out.println(this.name + " is playing...");
	}

	// 重载play
	public void play(String name) {
		System.out.println(this.name + " is playing xx with " + name);
	}

	/**
	 * getClass().getName() + "@" + Integer.toHexString(hashCode());
	 * 推荐实体类都覆写toString方法,方便查看日志信息
	 * 
	 * @return
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}

}

目标测试类
/**
 * 利用反射对目标类进行测试
 * 
 * @author [*昨日重现*] [email protected]
 * @since version 1.0
 * @datetime 2015年4月26日 下午5:14:52
 */

public class StudentTest {

	@BeforeClass
	public static void beforeClass() {
		System.out.println("=========在所有测试方法执行前执行--beforeClass=====\n");
	}

	/**
	 * 1、Class.forName("类的完整路径");2、Student.class;3、obj.getClass()
	 * 
	 * @throws Exception
	 */
	@Test
	public void testInfo() throws Exception {
		Class<?> c1 = Class.forName("com.leo.reflection.Student");
		// Class<?> c1 = Student.class;
		// 获取其实例,newInstance()会默认调用无参构造器,因此需要目标类保留无参的构造器
		Student s1 = (Student) c1.newInstance();
		// System.out.println("s1 = " + s1.getClass().getCanonicalName());
		s1.info();
		int age = s1.getAge();
		String name = s1.getName();
		Assert.assertThat(age, Matchers.is(22));// normal
		Assert.assertThat(name, Matchers.is("李四"));// failure
	}

	/**
	 * 通过类的加载器来获取某个类
	 * 
	 * @throws Exception
	 */
	@Test
	public void testInfo2() throws Exception {
		// 获取一个类加载器
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		// 加载指定的类
		Class<?> clazz = cl.loadClass("com.leo.reflection.Student");
		// System.out.println(clazz.getName());
		Student s1 = (Student) clazz.newInstance();
		s1.info();
	}

	/**
	 * 访问构造器
	 * 
	 * @throws Exception
	 */
	@Test
	public void testConstruction() throws Exception {
		Class<?> c1 = Class.forName("com.leo.reflection.Student");
		// 获取带有指定参数列表的构造方法的Constructor对象
		Constructor<?> cs = c1.getDeclaredConstructor(String.class,
				Integer.class);
		Student s1 = (Student) cs.newInstance("小四", 24);
		s1.info();

		// 获取指定类的所有构造器
		// Constructor<?>[] constructors = c1.getDeclaredConstructors();
		// for (Constructor<?> constructor : constructors) {
		// System.out.println("constructor = " + constructor);
		// }
	}

	/**
	 * 访问属性(包括私有属性)
	 * 
	 * @throws Exception
	 */
	@Test
	public void testField() throws Exception {
		Class<?> c1 = Class.forName("com.leo.reflection.Student");
		Student s1 = (Student) c1.newInstance();
		
		// 获取某个属性
		Field field = c1.getDeclaredField("name");
		// 该属性设置为可访问
		field.setAccessible(true);
		System.out.println("field = " + field + " , " + field.get(s1));

		// 获取指定类的所有属性
		// Field[] fields = c1.getDeclaredFields();
		// for (Field f : fields) {
		// f.setAccessible(true);
		// System.out.println(f.getName() + " = " + f.get(s1));
		// }

	}

	/**
	 * 访问方法(包括私有方法)
	 * 
	 * @throws Exception
	 */
	@Test
	public void testMethod() throws Exception {
		Class<?> c1 = Class.forName("com.leo.reflection.Student");
		Student s1 = (Student) c1.newInstance();

		// 获取某个类的指定无参方法
		Method m1 = c1.getDeclaredMethod("play");
		m1.invoke(s1);

		// 获取某个类的指定含参方法
		Method m2 = c1.getDeclaredMethod("play", String.class);
		m2.invoke(s1, "钱七");

		System.out.println("=======================");
		// 获取指定类的所有方法
		// Method[] methods = c1.getDeclaredMethods();
		// for (Method method : methods) {
		// method.setAccessible(true);
		// System.out.println(method.getName());
		// }
		// System.out.println("=======================\n");

	}

	@AfterClass
	public static void afterClass() {
		System.out.println("==========在所有测试方法执行后执行--afterClass=====\n");
	}

}
 
 

总结

1、所有类的对象其实都是Class的实例。
2、Class实例化其他类的对象的时候,一定要保留默认的无参构造函数。
3、加载某个类的3种常用方式:a) Class.forName("类的完整路径")、b) 类名.class、c) obj.getClass()
4、反射的常用的两步:Class<?> c1 = Class.forName("类的完整路径");T1 t = (T1) c1.newInstance();

猜你喜欢

转载自jave-lover.iteye.com/blog/2209568