1. 反射概念
功能:通过放射获取任何一个类加载到内存对象所属类、类的对象、成员变量方法、在动态代理中有用
放射API:
java.lang.Class : 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field : 代表类的成员变量
java.lang.reflect.Constructor: 代表类的构造方法
反射源头: java.lang.Class
创建一个类,通过java.exe编译以后,对应.class,之后我们使用JVM加载器加载内存中,
此时.class类加载到内存以后,是一个运行时类,存在缓存区, 每一个类都是一个java.lang.Class
实例, 这个实例可以获取运行时类的完整结构(属性、方法、父类、异常)、调用对应方法
2. 反射基础API
2.1.通过反射类中调用 属性、方法类
Parent.java
package com.denganzhi.bb; public class Parent<T> { }Person.java
package com.denganzhi.bb; import java.io.File; import java.io.IOException; import java.io.Serializable; import javax.xml.ws.Action; import javax.xml.ws.soap.Addressing; @Addressing public class Person extends Parent<String> implements Serializable{ public int age; private int sex; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(String name) { super(); this.name = name; } @Action public void dislay(String str) throws IOException{ //File file=new File(""); //file.createNewFile(); System.out.println("我是display...:"+str); } private void dislay2(String str) { System.out.println("我是display...:private"); } public Person() { super(); } public static void showDis(){ System.out.println("静态方法"); } }代码区域:
package com.denganzhi.bb; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Properties; import org.junit.Test; public class Main { // 通过反射调用 属性、方法类 @Test public void test1() throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException, IOException{ // 方法1:获取clazz 对应运行时候类 //Class clazz= Person.class; // 方法2: // Person person=new Person(); // Class clazz= person.getClass(); //方法3: //Class clazz= Class.forName("com.denganzhi.bb.Person"); // 方式4: 通过类加载器 ClassLoader classloader=this.getClass().getClassLoader(); Class clazz=classloader.loadClass("com.denganzhi.bb.Person"); // classloader加载文件,从当前包路径下加载资源文件, jdbc.properties在com.denganzhi.bb包下 //InputStream inputstream=classloader.getSystemResourceAsStream("com\\denganzhi\\bb\\jdbc.properties"); // 本地路径,项目工程下 InputStream inputstream=new FileInputStream(new File("jdbc2.properties")); Properties properties=new Properties(); properties.load(inputstream); System.out.println(properties.getProperty("username")); Person p=(Person) clazz.newInstance(); // 获取属性Field对象 /** * 1.public: * 相当于 p.age=100 * 访问:p.age */ Field ageField= clazz.getField("age"); ageField.set(p, 100); System.out.println(ageField.get(p)); /* * 2.private */ Field age2File= clazz.getDeclaredField("sex"); age2File.setAccessible(true); // 破坏private age2File.set(p, 1); System.out.println(age2File.get(p)); /*** * 3. 通过反射获取方法 * 方法名称、参数类型 */ Method m1= clazz.getMethod("dislay", String.class); m1.invoke(p, "xiaoming"); /** * private方法 */ Method m11= clazz.getDeclaredMethod("dislay2", String.class); m11.setAccessible(true); m11.invoke(p, "xiaoming"); /** * 静态方法 */ Method m2= clazz.getMethod("showDis"); m2.invoke(Person.class); /** * 调用指定构器 */ Constructor cons=clazz.getDeclaredConstructor(String.class); Person newp=(Person) cons.newInstance("小泽"); System.out.println(newp.getName()); } }2.2.通过反射获取类中定义的属性
// 获取属性结构 @Test public void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException{ Class clazz= Class.forName("com.denganzhi.bb.Person"); // 获取运行时类的对象 Object obj= clazz.newInstance(); // 调用Person类的无参构造函数,构造函数非private // 获取所有属性public Field[] fields= clazz.getFields(); for (int i = 0; i < fields.length; i++) { // 获取修饰符 public int k= fields[i].getModifiers(); String kstr=Modifier.toString(k); System.out.println("修饰符:"+kstr); // 获取属性名类型 int Class type= fields[i].getType(); System.out.println(type.getName()+""); System.out.println(fields[i]); } // 运行时候类本身的所有属性 Field[] fields2= clazz.getDeclaredFields(); for (int i = 0; i < fields2.length; i++) { //System.out.println(fields2[i]); } }2.3. 通过反射获取类中定义的方法
@Test public void test3() throws ClassNotFoundException{ // 获取运行时候类的方法以及父类声明为public的方法 Class clazz= Person.class; Method[] m1= clazz.getMethods(); for (int i = 0; i < m1.length; i++) { // System.out.println(m1[i]); } // 本身声明的所有方法 Method[] m2= clazz.getDeclaredMethods(); for (int i = 0; i < m2.length; i++) { System.out.println("======================================="); System.out.println(m2[i]); // 1. 注释 Annotation[] ann= m2[i].getAnnotations(); for (Annotation annotation : ann) { System.out.println(annotation); } // 2. 权限修饰符 System.out.println(Modifier.toString(m2[i].getModifiers())); // 3. 返回值 Class<?> returnRype=m2[i].getReturnType(); System.out.println(returnRype); // 4.方法名 System.out.println(m2[i].getName()); // 5. 形参列表 System.out.print("("); Class[] params= m2[i].getParameterTypes(); for (Class class1 : params) { System.out.print(class1.getName()); } System.out.println(")"); // 6. 异常类型 Class[] exceptionType= m2[i].getExceptionTypes(); for (Class class1 : exceptionType) { System.out.println(class1.getName()); } } System.out.println("====================================="); // 9. 获取构造器 Constructor<?>[] cons=clazz.getDeclaredConstructors(); for (Constructor<?> constructor : cons) { System.out.println("构造器: "+constructor); } }2.4. 通过反射获取父类
@Test public void test4(){ Class clazz= Person.class; System.out.println(clazz.getSuperclass());// 父类 System.out.println(clazz.getGenericSuperclass()); // 带泛型父类 ParameterizedType param= (ParameterizedType)clazz.getGenericSuperclass(); Type[] ars= param.getActualTypeArguments(); // 泛型类型 System.out.println((Class)ars[0]); // 获取父类的方泛型,在jdbc获取basedao父类,然后实例化对象 // 获取实现接口 Class[] interfaceClass= clazz.getInterfaces(); for (Class class1 : interfaceClass) { System.out.println(class1); } // 获取所在的包 System.out.println(clazz.getPackage()); // 类获取类的注解 Annotation[] anns= clazz.getAnnotations(); for (Annotation annotation : anns) { System.out.println(annotation); } }3. 反射应用
3.1. 静态代理,传入实例对象,代理类中调用方法【只能买房】
package com.denganzhi.dongtai; //静态代理模式 //接口 interface ClothFactory{ void productCloth(); } //被代理类 class NikeClothFactory implements ClothFactory{ @Override public void productCloth() { System.out.println("Nike工厂生产一批衣服"); } } //代理类 class ProxyFactory implements ClothFactory{ ClothFactory cf; //创建代理类的对象时,实际传入一个被代理类的对象 public ProxyFactory(ClothFactory cf){ this.cf = cf; } @Override public void productCloth() { System.out.println("代理类开始执行,收代理费$1000"); cf.productCloth(); } } public class TestClothProduct { public static void main(String[] args) { NikeClothFactory nike = new NikeClothFactory();//创建被代理类的对象 ProxyFactory proxy = new ProxyFactory(nike);//创建代理类的对象,传入被代理类对象即可 proxy.productCloth(); // 调用代理类方法 } }3.2. 动态代理【可以在代理中买房、买车】
package com.denganzhi.dongtai; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //动态代理的使用,体会反射是动态语言的关键 interface Subject { void action(); } // 被代理类1 class RealSubject implements Subject { public void action() { System.out.println("我要买房子"); } } class BuyCar implements Subject { public void action() { System.out.println("我要买车子"); } } class MyInvocationHandler implements InvocationHandler { Object obj;// 实现了接口的被代理类的对象的声明 // ①给被代理的对象实例化②返回一个代理类的对象 public Object blind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } //当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method方法的返回值时returnVal Object returnVal = method.invoke(obj, args); return returnVal; } } public class TestProxy { public static void main(String[] args) { //1.被代理类的对象 RealSubject real = new RealSubject(); BuyCar buycar = new BuyCar(); //2.创建一个实现了InvacationHandler接口的类的对象 MyInvocationHandler handler = new MyInvocationHandler(); //3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。 // 被代理类1,买房 Object obj = handler.blind(real); Subject sub = (Subject)obj;//此时sub就是代理类的对象 sub.action();//转到对InvacationHandler接口的实现类的invoke()方法的调用 // 被代理类2,买车 Object obj1 = handler.blind(buycar); Subject sub1 = (Subject)obj1;//此时sub就是代理类的对象 sub1.action(); } }3.3.动态代理实际应用,AOP 【打印日志例子】
package com.denganzhi.dongtai; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Human { void info(); void fly(); } // 被代理类 class SuperMan implements Human { public void info() { System.out.println("打印日志中1"); } public void fly() { System.out.println("打印日志中2"); } } class HumanUtil { public void method1() { System.out.println("=======插入的方法一打印日志前======="); } public void method2() { System.out.println("=======插入的方法二打印日志后======="); } } class MyInvocationHandler implements InvocationHandler { Object obj;// 被代理类对象的声明 public void setObject(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { HumanUtil h = new HumanUtil(); h.method1(); Object returnVal = method.invoke(obj, args); h.method2(); return returnVal; } } class MyProxy { // 动态的创建一个代理类的对象 public static Object getProxyInstance(Object obj) { MyInvocationHandler handler = new MyInvocationHandler(); handler.setObject(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), handler); } } public class TestAOP { public static void main(String[] args) { SuperMan man = new SuperMan();//创建一个被代理类的对象 Object obj = MyProxy.getProxyInstance(man);//返回一个代理类的对象 Human hu = (Human)obj; hu.info();//通过代理类的对象调用重写的抽象方法 hu.fly(); } }4.类载器层次结构:
Bootstap Classloader : 引导类加载器,用于加载jdk中api类 ,无法通过api获取
↑ 父类
Extension Classloader : 扩展类加载器,用于加载jre/lib/ext目录下jar包,或者第三方jar包
↑ 父类
System Classloader: 系统类加载器,用于加载用户写的类
Class class1= Class.forName("com.dengnzhi.test.Student");
Student student = (Student) class1.newInstance();
System.out.println("系统类加载器:"+class1.getClassLoader());
System.out.println("扩张类加载器:"+class1.getClassLoader().getParent());
System.out.println("引导类加载器:"+class1.getClassLoader().getParent().getParent());
系统类加载器:sun.misc.Launcher$AppClassLoader@73d16e93
扩张类加载器:sun.misc.Launcher$ExtClassLoader@6d06d69c
引导类加载器:null