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();//代理类对象调用接口中声明的方法
		
	}
}

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

第十五章 反射

相关文章: