返回顶部
扩大
缩小

Heaton

第十五章 反射

15、反射
15.1 Java反射机制概述 1课时
15.2 理解Class类并获取Class类的实例 1课时
15.3 类的加载与ClassLoader的理解 1课时
15.4 通过反射创建运行时类的对象 1课时
15.5 通过反射获取运行时类的完整结构 1课时
15.6 通过反射调用运行时类的指定属性、指定方法等 1课时
15.7 反射的应用:动态代理 1课时
##15-1 Java反射机制概述


案例

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;

import javax.swing.plaf.synth.SynthSliderUI;

import org.junit.Test;

/**
 * 本章要涉及的内容:
 * 
 * 1.反射的概述 
 * 2.Class的理解 和 实例化  (掌握)
 * 3.类的加载和ClassLoader的理解
 * 4.使用反射,创建指定的运行时类的对象  (掌握)
 * 5.使用反射,获取运行时类中的所有的结构:属性、方法、构造器、父类、接口、注解、父类的泛型... 
 * 6.使用反射,调用运行时类中的指定的结构:属性、方法、构造器   (掌握)
 * 7.反射的应用:动态代理,体会反射的动态性。
 * 
 */
public class ReflectionTest {
	
	/**
	 * Properties:常用来处理属性文件。
	 * @throws IOException 
	 * 
	 * 
	 */
	@Test
	public void test5() throws IOException{
		//处理工程下的配置信息
		Properties pros = new Properties();
		//默认文件的读取位置:当前工程下。
//		FileInputStream is = new FileInputStream("jdbc.properties");
		FileInputStream is = new FileInputStream("src\\jdbc1.properties");
		pros.load(is);
		
		String name = pros.getProperty("name");
		String password = pros.getProperty("password");
		System.out.println("name = " + name + ",password = " + password);
		
		
		System.out.println("**************************************");
		Properties pros1 = new Properties();
		ClassLoader loader = ReflectionTest.class.getClassLoader();
		//默认读取配置文件的位置是:src目录下
//		InputStream inputStream = loader.getResourceAsStream("jdbc1.properties");
		InputStream inputStream = loader.getResourceAsStream("com\\xxx\\java\\jdbc2.properties");
		pros1.load(inputStream);
		
		String user = pros1.getProperty("name");
		String pwd = pros1.getProperty("password");
		System.out.println("user = " + user + ",pwd = " + pwd);
	}
	
	/**
	 * 了解类的加载过程 和 类的加载器:ClassLoader
	 * @throws ClassNotFoundException 
	 * 
	 * 
	 */
	@Test
	public void test4() throws ClassNotFoundException{
		//获取系统类加载器
		ClassLoader classLoader1 = ClassLoader.getSystemClassLoader();
		System.out.println(classLoader1);
		
		//获取扩展类加载器
		ClassLoader classLoader2 = classLoader1.getParent();
		System.out.println(classLoader2);
		
		//获取引导类加载器(获取不到)
		ClassLoader classLoader3 = classLoader2.getParent();
		System.out.println(classLoader3);
		
		//说明:用户自定义类是由系统类加载器加载的
		ClassLoader loader1 = Person.class.getClassLoader();
		System.out.println(loader1);
		//说明:java 核心api是由引导类加载器加载的
		ClassLoader loader2 = Class.forName("java.lang.String").getClassLoader();
		System.out.println(loader2);
		
	}
	
	/**
	 * java.lang.Class的理解
	 * 1.Class是反射的源头
	 * 2.java源程序经过编译(javac.exe)以后,生成一个或多个字节码(.class)文件,我们使用java.exe命令,
	 * 将指定的字节码文件加载到内存中,解释运行。此过程是使用JVM的类的加载器、解释器等实现的。
	 * 加载到内存中的字节码文件对应的类,称为运行时类,此运行时类,即为一个Class的实例。
	 * 
	 * 3.Class的一个实例,对应着一个加载内存中的运行时类。
	 * 
	 * 4.加载到内存中的运行时类,只被类的加载器加载器一次,之后会被缓存下来。
	 * 
	 * @throws ClassNotFoundException 
	 * @throws Exception
	 */
	//如何获取Class的实例 (4种)
	@Test
	public void test3() throws ClassNotFoundException{
		//方式一(掌握):调用运行时类的属性:.class
		Class clazz1 = Person.class;
		System.out.println(clazz1);
		
		//方式二(掌握):可以调用运行时类对象的getClass()
		Person p = new Person();
		Class clazz2 = p.getClass();
		System.out.println(clazz2);
		
		//方式三(掌握):调用Class类的静态方法:forName(String className).
		//注释:className需要提供类的全类名
		Class clazz3 = Class.forName("com.xxx.java.Person");
		System.out.println(clazz3);
		
		System.out.println(clazz1 == clazz2 && clazz1 == clazz3);
		
		//方式四(了解):使用类的加载器(ClassLoader)
		ClassLoader classLoader = ReflectionTest.class.getClassLoader();
		Class clazz4 = classLoader.loadClass("com.xxx.java.Person");
		System.out.println(clazz4);
		System.out.println(clazz1 == clazz4);
		
	}
	
	
	//有了反射以后,类的封装性受到影响了。如何理解这两个技术?
	//单例模式被打破了?!
	
	//通过反射,实现Person类对象的创建,属性、方法的调用
	@Test
	public void test2() throws Exception{
		
		Class clazz = Person.class;
		//通过反射,调用指定的构造器,创建运行时类Person类的对象
		Constructor con = clazz.getConstructor(String.class,int.class);
		Person p = (Person) con.newInstance("Tom",12);
		
		System.out.println(p);
		
		//通过反射,调用当前对象的指定的属性
		Field field1 = clazz.getField("name");
		field1.set(p, "HanMeimei");
		
		//通过反射,调用当前对象的指定的方法
		Method method1 = clazz.getMethod("show");
		method1.invoke(p);
		
		System.out.println("***********************************");
		//通过反射,调用运行时类Person类的私有的构造器
		Constructor con1 = clazz.getDeclaredConstructor(String.class);
		con1.setAccessible(true);
		Person p1 = (Person) con1.newInstance("田杰");
		
		System.out.println(p1);
		
		//通过反射,调用运行时类Person类的私有的属性
		Field field2 = clazz.getDeclaredField("age");
		field2.setAccessible(true);
		field2.set(p1, 23);
		
		System.out.println(p1);
		
		
		//通过反射,调用运行时类Person类的私有的方法
		Method method2 = clazz.getDeclaredMethod("display",String.class);
		method2.setAccessible(true);
		String info = (String) method2.invoke(p1, "中国");//此invoke()的返回值,即为对应的display()的返回值
		
		System.out.println(info);
		
	}
	
	//反射之前的体会
	@Test
	public void test1(){
//		Person p = new Person("Tom");//不可直接调用
		Person p1 = new Person("Tom", 12);
		
		p1.name = "HanMeimei";
//		p1.age = 10;//不可直接调用
		
		p1.show();
//		p1.display("CHN");//不可直接调用
		
		Person p2 = new Person("Tim", 12);
		
	}
}

public class Person {
	public String name;
	private int age;
	
	public Person(){
		System.out.println("Person()");
	}
	private Person(String name){
		this.name = name;
	}
	
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}

	public void show(){
		System.out.println("name = " + name + ",age = " + age);
	}
	
	public String info(){
		return name + ":" + age;
	}
	
	private String display(String nation){
		System.out.println("我是" + nation + "国家的人");
		return nation;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	
}

jdbc.properties

name=\u62c9\u54c8\u5475

password=abc123


反射的应用一案例
import org.junit.Test;
/**
 * 反射的应用一:创建运行时类的对象 (掌握)
 * 
 */
public class NewInstanceTest {
	//有了Class实例以后,可以做什么呢?
	//可以创建运行时类的对象。
	@Test
	public void test1() throws Exception{
		
		Class clazz = Class.forName("com.tzy.java.Person");
		/*
		 * 1.newInstance():实际上调用的就是运行时类中的空参的构造器
		 * 2.可能调用,也要受封装性的影响。
		 * 
		 * 说明:建议创建的Bean类,都提供空参的构造器,而且权限一般都为public!
		 *     应用场景:①默认子类的构造器通过super()的方式,调用父类空参的构造器。
		 *     		  ②方便通过反射的方式,创建运行时类的对象
		 * 
		 */
		Person p = (Person) clazz.newInstance();
		
		System.out.println(p);
		
	}
}

15-2 理解Class类并获取Class的实例

15-3 类的加载ClassLoader的理解

15-4 创建运行时类的对象


15-5 获取运行时类的完整结构

15-6 调用运行时类的指定属性、指定方法等


反射总结案例

import java.io.Serializable;

public class Creature<T> implements Serializable {
	
	public boolean gender;
	double weight;
	
	public void play(T t){
		System.out.println("Creature");
	}

}

public interface MyInterface {
	String info();
	
}

import static java.lang.annotation.ElementType.CONSTRUCTOR; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	String value();
}

@MyAnnotation(value="xxxx") public class Person extends Creature implements Comparable,MyInterface{
	public String name;
	private int age;
	
	private static String nation = "CHN";
	
	public Person(){
		System.out.println("Person()");
	}
	private Person(String name){
		this.name = name;
	}
	
	protected Person(String name,int age){
		this.name = name;
		this.age = age;
	}

	@MyAnnotation(value="hello")
	public void show() throws RuntimeException{
		System.out.println("name = " + name + ",age = " + age);
	}
	
	public String info(){
		return name + ":" + age;
	}
	
	private String display(String nation){
		System.out.println("我是" + nation + "国家的人");
		return nation;
	}
	@Override
	@MyAnnotation(value="hi")
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	@Override
	public int compareTo(Person o) {
		// TODO Auto-generated method stub
		return 0;
	}
	
	public static void showNation(){
		System.out.println("我是中国人!");
	}
	
	
}

/** * 反射的应用二:获取运行时类的所有的结构:属性 * */ public class FieldTest {
	//如何获取运行时类中所有属性
	@Test
	public void test1(){
		
		Class clazz = Person.class;
		//getFields():只能获取当前运行时类,及其所有父类中声明为public的属性
		Field[] fields = clazz.getFields();
		for(int i = 0;i < fields.length;i++){
			System.out.println(fields[i]);
		}
		
		System.out.println("*****************");
		//getDeclaredFields():能够获取当前运行时类中声明的所有的属性,不论权限的大小。
		Field[] fields1 = clazz.getDeclaredFields();
		for(int i = 0;i < fields1.length;i++){
			System.out.println(fields1[i]);
		}
		
	}
	
	//权限修饰符  数据类型 变量名
	@Test
	public void test2(){
		Class clazz = Person.class;
		Field[] fields = clazz.getDeclaredFields();
		for (Field f : fields) {

			// 1.权限修饰符
			int modifier = f.getModifiers();
//			System.out.println(modifier);
			System.out.print(Modifier.toString(modifier) + "\t");
//
//			// 2.类型
			Class type = f.getType();
			System.out.print(type.getName() + "\t");
//
//			// 3.变量名
			System.out.println(f.getName());
		}
	}
	
}

/** * 反射的应用二:获取运行时类的所有的结构:方法 */ public class MethodTest {
	// 获取运行时类中声明的所有的方法
	@Test
	public void test1() {

		Class clazz = Person.class;

		// getMethods():获取当前运行时类,及其所有的父类中声明为public的方法
		Method[] methods = clazz.getMethods();
		for (Method m : methods) {
			System.out.println(m);
		}
		System.out.println("*********************");
		// getDeclaredMethods():获取当前运行时类中声明的所有的方法,不论权限的大小
		Method[] methods1 = clazz.getDeclaredMethods();
		for (Method m : methods1) {
			System.out.println(m);
		}

	}

	// 注解
	// 权限修饰符 返回值类型 方法名(参数类型1 参数名1,参数类型2 参数名2,...) throws 异常类型1,异常类型2,...{}
	@Test
	public void test2() {
		Class clazz = Person.class;

		Method[] methods = clazz.getDeclaredMethods();
		for (Method m : methods) {
			// 1.注解
			Annotation[] annos = m.getAnnotations();
			for (Annotation a : annos) {
				System.out.println(a);
			}
			// 2.权限修饰符
			System.out.print(Modifier.toString(m.getModifiers()) + "\t");
			// 3. 返回值类型
			Class returnType = m.getReturnType();
			System.out.print(returnType.getName() + "\t");

			// 4.方法名
			System.out.print(m.getName() + "(");

			// 5.(形参类型 变量名,....)
			Class[] paras = m.getParameterTypes();
			for (int i = 0; i < paras.length; i++) {
				if (i == paras.length - 1) {
					System.out.print(paras[i].getName() + " args_" + i);
					break;
				}
				System.out.print(paras[i].getName() + " args_" + i + ",");
			}

			System.out.print(")");

			// 6. 异常类型
			Class[] exceptionTypes = m.getExceptionTypes();
			if (exceptionTypes != null && exceptionTypes.length != 0) {
				System.out.print(" throws ");
			}

			for (Class c : exceptionTypes) {
				System.out.print(c.getName() + "\t");
			}

			System.out.println();
		}
	}
}

/** * 反射的应用二:获取运行时类的所有的结构:构造器 */ public class ConstructorTest {
	@Test
	public void test1(){
		Class clazz = Person.class;
		
		//getConstructors():获取运行时类中声明为public权限的构造器
		Constructor[] cons = clazz.getConstructors();
		for(Constructor c : cons){
			System.out.println(c);
		}
		
		System.out.println("*********************");
		//getDeclaredConstructors():获取运行时类中所有的构造器,不论权限大小
		Constructor[] cons1 = clazz.getDeclaredConstructors();
		for(Constructor c : cons1){
			System.out.println(c);
		}
		
		
	}
}

/** * 反射的应用二:获取运行时类的所有的结构:其它结构 */ public class OtherTest {
	//获取运行时类所实现的接口
	@Test
	public void test5(){
		Class clazz = Person.class;
		
		Class[] interfaces = clazz.getInterfaces();
		for(Class c : interfaces){
			System.out.println(c);
		}
	}
	
	
	@Test
	public void testGetSuperClassGenericParam() throws Exception{
		String className = "com.xxx.java1.Person";
		className = "com.xxx.java2.CustomerDAO";
		className = "com.xxx.java2.OrderDAO";
		String superClassGenericParam = getSuperClassGenericParam(className);
		System.out.println(superClassGenericParam);
	}
	
	//体会反射的动态性
	public String getSuperClassGenericParam(String className) throws Exception{
		
		Class clazz = Class.forName(className);
		Type genericSuperClass = clazz.getGenericSuperclass();
		ParameterizedType paramsType = (ParameterizedType) genericSuperClass;
		Type[] arguments = paramsType.getActualTypeArguments();
		return ((Class)arguments[0]).getName();
		
	}
	
	//获取运行时类的带泛型的父类的泛型
	//逻辑性代码     功能性代码
	@Test
	public void test4(){
		Class clazz = Person.class;
		
		Type genericSuperClass = clazz.getGenericSuperclass();
		ParameterizedType paramsType = (ParameterizedType) genericSuperClass;
		Type[] arguments = paramsType.getActualTypeArguments();
		System.out.println(((Class)arguments[0]).getName());
		
	}
	
	//获取运行时类的带泛型的父类
	@Test
	public void test3(){
		Class clazz = Person.class;
		
		Type genericSuperClass = clazz.getGenericSuperclass();
		System.out.println(genericSuperClass);
	}
	
	//获取运行时类的父类
	@Test
	public void test2(){
		Class clazz = Person.class;
		
		Class superClass = clazz.getSuperclass();
		System.out.println(superClass);
		
		Class superClass1 = superClass.getSuperclass();
		System.out.println(superClass1);
	}	
	
	//获取运行时类所属的包
	@Test
	public void test1(){
		Class clazz = Person.class;
		
		Package pack = clazz.getPackage();
		System.out.println(pack);
	}
}

/** * 反射的应用三:调用运行时类中的指定的结构:属性、方法、构造器 (掌握) */ public class ReflectionTest { //int i = 10; Integer j = i; //如何调用运行时类的指定的构造器 (模板代码) @Test public void test4() throws Exception{ Class clazz = Person.class; //第一步:getDeclaredConstructor(Class ... params): Constructor con = clazz.getDeclaredConstructor(String.class,int.class); // Constructor con = clazz.getDeclaredConstructor(String.class,Integer.class);//不可以使用Integer替换类声明的int型参数 //第二步:setAccessible(true):保证当前的构造器是可操作的 con.setAccessible(true);
		//第三步:newInstance(Object paramValue):调用构造器,创建运行时类的对象
		Person p = (Person) con.newInstance("田杰",23);
		
		System.out.println(p);
		
	}
	
	
	//如何调用运行时类的指定的方法 (模板代码)
	@Test
	public void test3() throws Exception{
		Class clazz = Person.class;
		
		//第一步:getDeclaredMethod(String methodName,Class ... params):获取当前运行时类中指定的方法
		Method m1 = clazz.getDeclaredMethod("display",String.class);
		
		//2.第二步:setAccessible(true):保证当前的方法是可操作的
		m1.setAccessible(true);
		//3.第三步:invoke(Object obj,Object ... objs):调用此方法
		//此invoke()方法的返回值即为对应的要调用的方法的返回值。
		Person person = (Person) clazz.newInstance();
		String info = (String) m1.invoke(person,"中国");
		System.out.println(info);
		
		//另例:静态方法如何调用?
		Method m2 = clazz.getDeclaredMethod("showNation");
		m2.setAccessible(true);
//		m2.invoke(Person.class);
		m2.invoke(null);
		
		
	}
	
	
	//如何调用 运行时类的指定的属性 (模板代码)
	@Test
	public void test2() throws Exception{
		Class clazz = Person.class;
		//第一步:getDeclaredField(String fieldName):获取当前类中声明的属性,不用考虑权限
		Field f1 = clazz.getDeclaredField("age");
		System.out.println(f1);
		//创建运行时类的对象
		Person person = (Person) clazz.newInstance();
		
		//第二步:setAccessible(true):保证当前的属性是可操作的
		f1.setAccessible(true);
		//第三步:对属性进行设置获取
		//1.如何设置当前属性的值
		f1.set(person, 12);
		
		//2.如何获取当前属性的值
		int age = (int) f1.get(person);
		System.out.println(age);
		
		//另例:如何调用静态的属性?
		Field f2 = clazz.getDeclaredField("nation");
		f2.setAccessible(true);
		f2.set(null, "CHINA");
		System.out.println(f2.get(null));
		
		
	}
	
	//如何调用 运行时类的指定的属性  (不用练了)
	@Test
	public void test1() throws Exception{
		Class clazz = Person.class;
		//getField(String fieldName):
		Field f1 = clazz.getField("name");
		System.out.println(f1);
		//创建运行时类的对象
		Person person = (Person) clazz.newInstance();
		
		//如何设置当前属性的值
		f1.set(person, "Tom");
		
		//如何获取当前属性的值
		String name = (String) f1.get(person);
		System.out.println(name);
	}
	
}

15-7 反射的应用:动态代理

静态代理案例

/**
 * 静态代理的例子1:如下
 * 
 * 静态代理的例子2:实现Runnable接口的方式,就是代理模式
 *
 */
public class ClothFactoryTest {
	public static void main(String[] args) {
		
		NikeClothFactory nikeFactory = new NikeClothFactory();//创建被代理类对象
		ProxyClothFactory proxy = new ProxyClothFactory(nikeFactory);//创建代理类对象
		proxy.produceCloth();
	}
}


interface ClothFactory{
	
	void produceCloth();
}

//代理类
class ProxyClothFactory implements ClothFactory{

	ClothFactory clothFactory;
	
	public ProxyClothFactory(ClothFactory clothFactory){
		this.clothFactory = clothFactory;
	}
	
	@Override
	public void produceCloth() {
		System.out.println("代理工厂需要进行前期准备操作");
		
		clothFactory.produceCloth();
		
		System.out.println("代理工厂需要进行后期处理操作");
	}
	
	
	
	
}

//被代理类
class NikeClothFactory implements ClothFactory{

	@Override
	public void produceCloth() {
		System.out.println("Nike工厂生产一批衣服");
	}
	
}

动态代理案例

/**
 * 动态代理的例子
 */

interface Human{
	
	String say();
	
	void fly();
	
}

//被代理类
class SuperMan implements Human{

	@Override
	public String say() {
		return "我是超人!我怕谁!";
	}

	@Override
	public void fly() {
		System.out.println("I believe I can fly!");
	}
	
}


class HumanUtil{
	
	public void method1(){
		System.out.println("==========通用的操作一=================");
		
	}
	
	public void method2(){
		System.out.println("==========通用的操作二=================");
		
	}
}


/*
 * 要想实现动态代理类对象的功能,需要解决两个问题:
 * ①如何根据加载到内存中的被代理类对象,动态的去创建代理类的对象
 * ②如何通过代理类的对象调用接口中声明的方法时,实现对被代理类对象同名方法的调用
 * 
 */
class MyInvocationHandler implements InvocationHandler{
	
	private Object obj;//被代理类的对象
	
	public void bind(Object obj){//实例化被代理类的对象
		this.obj = obj;
	}
	
	
	//解决上述说明的问题②
	//当通过代理类的对象调用接口中的方法a时,就会调用如下的InvocationHandler中的invoke()
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		HumanUtil humanUtil = new HumanUtil();
		humanUtil.method1();
		
		
		//method:单行注释中的方法a
		Object returnVal = method.invoke(obj, args);
		
		humanUtil.method2();
		
		return returnVal;
	}
	
}

class ProxyFactory{
	
	//调用此方法,返回一个代理类的对象
	public static Object getProxyInstance(Object obj){//形参obj:被代理类的对象
		
		MyInvocationHandler handler = new MyInvocationHandler();
		handler.bind(obj);
		//解决上述说明的问题①
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), handler);
	}
	
}

public class ProxyTest {
	public static void main(String[] args) {
		
		SuperMan man = new SuperMan();//被代理类对象
		
		Object proxyObj = ProxyFactory.getProxyInstance(man);//proxyObj:代理类对象
		
		Human human = (Human) proxyObj;
		
		Object returnValue = human.say();//代理类对象调用接口中声明的方法
		System.out.println(returnValue);
		human.fly();
		
		System.out.println("****************");
		
		NikeClothFactory nike = new NikeClothFactory();
		ClothFactory proxy = (ClothFactory) ProxyFactory.getProxyInstance(nike);
		proxy.produceCloth();//代理类对象调用接口中声明的方法
		
	}
}

posted on 2018-10-05 13:47  咘雷扎克  阅读(171)  评论(0)    收藏  举报

导航