Java基础学习:反射篇
1.什么是反射?
Reflection(反射)是被视为动态语言的关键,反射机制允许程序做执行期间借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象内部属性及方法
2.反射相关的主要API
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法
3.简单入门示例代码
package day01.code; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.junit.Test; public class TestReflection { // 有了反射,可以通过反射创建一个类的对象,并调用其中的结构 @Test public void test2() throws Exception{ Class clazz=Person.class; // 1.创建clazz对应的运行时类Person类的对象 Person person= (Person)clazz.newInstance(); System.out.println(person); // 2.通过反射调用运行时类的指定的属性 // 2.1 调用public的属性 Field f1=clazz.getField("name"); f1.set(person, "lisi"); System.out.println(person); // 2.2 调用非public的属性 Field f2= clazz.getDeclaredField("age"); f2.setAccessible(true); f2.set(person, 20); System.out.println(person); // 3.通过反射调用运行时类的指定的方法 // 3.1 调用无参方法 Method m1=clazz.getMethod("show"); m1.invoke(person); // 3.2 调用有参方法 Method m2=clazz.getMethod("display",String.class); m2.invoke(person, "CHN"); } // 在有反射以前,如何创建一个类的对象,并调用其中的方法,属性 @Test public void test1(){ Person person=new Person(); person.setAge(10); person.setName("zhangsan"); System.out.println(person); person.show(); person.display("CN"); } }
4.反射的源头Class
4.1 getClass()详解,此方法中Object类中被定义,会被所有的子类继承,调用此方法返回值的类型是一个Class类,此类的反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射出类的名称
@Test public void test3(){ Person person=new Person(); Class calzz= person.getClass(); // 通过运行时类的对象,调用其getClass(),返回其运行时类 System.out.println(calzz); }
4.2 反射原理解析
我们创建了一个类,通过编译(javac.exe),生成对应的.class文件,之后我们使用java.exe加载(JVM的类加载器完成的)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存放在缓存区。那么这个运行时类本身就是一个Class的实例!
4.2.1 每一个运行时类只加载一次
4.2.2 有了Class的实例以后,我们才可以进行如下操作
1)创建对应的运行时类的对象
2)获取对应的运行时类的完整结构(属性,方法,构造器,内部类,父类,所在的包,异常,注解........)
3) 调用对应的运行时类的指定的结构(属性,方法,构造器)
4)反射的应用,动态代理
正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象
反射方式:实例化对象->getClass()方法->得到完整的“包类”名称
4.3 获取Class的实例
4.3.1 调用运行时类本身的.class属性
@Test public void test4(){ // 1.调用运行时类本身的.class属性 Class clazz=Person.class; System.out.println(clazz.getName()); }
4.3.2 通过运行时类的对象获取
@Test public void test5(){ // 通过运行时类的对象获取 Person person=new Person(); Class clazz= person.getClass(); System.out.println(clazz.getName()); }
4.3.3 通过Class的静态方法获取
@Test public void Test6() throws Exception{ // 通过Class的静态方法获取 String className="day01.code.Person"; Class clazz= Class.forName(className); System.out.println(clazz.getName()); }
4.3.4 通过类的加载器
@Test public void test7() throws Exception{ // 通过类的加载器 String className="day01.code.Person"; ClassLoader classLoader=this.getClass().getClassLoader(); Class clazz= classLoader.loadClass(className); System.out.println(clazz.getName()); }
4.4 什么是类的加载器?(ClassLoader)
解释:类加载器是用来把类(class)装载进内存的。JVM 规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)
4.4.1 Bootstap Classloader 引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来加载核心类库,该加载器无法直接获取
4.4.2 Extension Classloader 扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库 .
4.4.3 System Classloader 系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 ,是最常用的加载器
4.5 有了Class对象,能做什么?
4.5.1 newInstance() 作用: 创建对应的运行时类的对象,实际上就是调用类运行时类的空参的构造器。注:要想创建成功,1.要求对应的运行时类要有空参的构造器 2.构造器的权限修饰符的权限要足够(经验证同一个包下大于 private 即可)
@Test public void test1() throws Exception{ String className="day01.code.Person"; Class clazz= Class.forName(className); // 创建运行时对象 Object obj=clazz.newInstance(); Person person=(Person)obj; System.out.println(person); }
4.5.2 通过反射调用类的完整结构(实现的全部接口,所继承的父类,全部的构造器,全部的方法,全部的Field)
4.5.2.1 Field
// 获取对应的运行时类的属性 @Test public void test1(){ Class clazz= Person.class; // 1.getFields():只能获取到运行时类及其父类中声明为public的属性 Field[] fields=clazz.getFields(); for(int i=0;i<fields.length;i++){ System.out.println(fields[i]); } System.out.println(); // 2.getDeclaredFields():获取到运行时类本身声明的所有的属性 Field[] fields1=clazz.getDeclaredFields(); for (Field field : fields1) { System.out.println(field.getName()); } } // 权限修饰符 变量类型 变量名,获取属性的各个部分的内容 @Test public void test2(){ Class clazz= Person.class; Field[] fields1=clazz.getDeclaredFields(); for (Field field : fields1) { // 1.获取每个属性的权限修饰符 int i= field.getModifiers(); String modifier= Modifier.toString(i); System.out.print(modifier+" "); // 2.获取属性的变量类型 Class type=field.getType(); System.out.print(type.getName()+" "); // 3.获取属性名 System.out.println(field.getName()); } }
4.5.2.2 Method
// 1.获取运行时类的方法 @Test public void test1(){ Class clazz=Person.class; // 1.getMethods():获取运行时类及其父类中所有声明为public的方法 Method[]m1=clazz.getMethods(); for (Method method : m1) { System.out.println(method); } System.out.println(); // 2.getDeclaredMethods():获取运行时类本身声明的所有的方法 Method[]m2=clazz.getDeclaredMethods(); for (Method method : m2) { System.out.println(method); } } // 注解 权限修饰符 返回值类型 方法名 形参列表 异常 @Test public void test2(){ Class clazz=Person.class; Method[]m2=clazz.getDeclaredMethods(); for (Method method : m2) { // 1.注解 Annotation[] ann= method.getAnnotations(); for (Annotation annotation : ann) { System.out.print(annotation+" "); } // 2.权限修饰符 String str= Modifier.toString(method.getModifiers()); System.out.print(str+" "); // 3.返回值类型 Class returnType=method.getReturnType(); System.out.print(returnType.getName()+" "); // 4.方法名 System.out.print(method.getName()+" "); // 5.形参列表 System.out.print("("); Class[]params=method.getParameterTypes(); for (Class p : params) { System.out.print(p.getName()); } System.out.print(")"); // 6.异常类型 Class[]exps= method.getExceptionTypes(); for (Class exp : exps) { System.out.print(exp.getName()+" "); } System.out.println(); } }
4.5.2.3 构造器
// 获取运行时类的构造器 @Test public void test2()throws Exception{ String className="day01.code.Person"; Class clazz= Class.forName(className); Constructor[]cons=clazz.getDeclaredConstructors(); for (Constructor constructor : cons) { System.out.println(constructor); } }
4.5.2.4 其他结构
// 6.获取注解 @Test public void test6(){ Class clazz=Person.class; Annotation[]anns=clazz.getAnnotations(); for (Annotation annotation : anns) { System.out.println(annotation); } } // 5.获取所在的包 @Test public void test5(){ Class clazz=Person.class; Package package1=clazz.getPackage(); System.out.println(package1); } // 4.获取实现的接口 @Test public void test4(){ Class clazz=Person.class; Class[] interfaces=clazz.getInterfaces(); for (Class class1 : interfaces) { System.out.println(class1); } } // 3.获取父类的泛型 @Test public void test3(){ Class clazz=Person.class; Type type=clazz.getGenericSuperclass(); ParameterizedType param=(ParameterizedType) type; Type[]ars=param.getActualTypeArguments(); System.out.println(((Class)ars[0]).getName()); } // 2.获取带泛型的父类 @Test public void test2(){ Class clazz=Person.class; Type type=clazz.getGenericSuperclass(); System.out.println(type); } // 1.获取运行时类的父类 @Test public void test1(){ Class clazz= Person.class; Class superClass=clazz.getSuperclass(); System.out.println(superClass); }
4.5.3 反射的各种操作
4.5.3.1 调用运行时类指定的属性
// 调用运行时类中指定的属性 @Test public void test3() throws Exception{ Class clazz=Person.class; // 1.获取指定的属性,属性权限是public的 Field name=clazz.getField("name"); // 2.创建运行时类的对象 Person p=(Person)clazz.newInstance(); System.out.println(p); // 3.将运行时类的指定的属性赋值 name.set(p, "Jerry"); System.out.println(p); System.out.println(); Field age= clazz.getDeclaredField("age"); // 由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性值可以被操作 age.setAccessible(true); age.set(p, 10); System.out.println(p); }
4.5.3.2 调用运行时类指定的方法
// 调用运行时类中指定的方法 @Test public void test3() throws Exception{ Class clazz=Person.class; // getMethod(String methodName,Class...params):获取运行时类中声明为public的方法 Method m1=clazz.getMethod("show"); Person person=(Person)clazz.newInstance(); // 可以获取返回值 Object returnVal=m1.invoke(person); System.out.println(returnVal); Method m2=clazz.getMethod("toString"); Object returnVal2=m2.invoke(person); System.out.println(returnVal2); // 获取运行时类的静态方法 Method m3=clazz.getMethod("info"); m3.invoke(Person.class); // getDeclaredMethod(String methodName,Class...params):获取运行时类中定义的方法 Method m4=clazz.getDeclaredMethod("display",String.class,Integer.class); m4.setAccessible(true); Object value= m4.invoke(person,"中国",10); System.out.println(value); }
4.5.3.3 调用指定的构造器
// 调用指定的构造器,创建运行时类的对象 @Test public void test() throws Exception{ String className="day01.code.Person"; Class clazz= Class.forName(className); Constructor cons= clazz.getDeclaredConstructor(String.class,int.class); cons.setAccessible(true); Person person=(Person)cons.newInstance("陆虎",10); System.out.println(person); }
4.5.4 动态代理vs静态代理
4.5.4.1 静态代理
package day01.code1; // 静态代理 // 接口 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("代理类开始执行。。。"); this.cf.productCloth(); } } public class TestClothProduct { public static void main(String[]args){ NikeClothFactory nikeClothFactory=new NikeClothFactory(); ProxyFactory proxyFactory=new ProxyFactory(nikeClothFactory); proxyFactory.productCloth(); } }
4.5.4.2 动态代理
package day01.code1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Subject{ void action(); } // 被代理类 class RealSubject implements Subject{ @Override public void action() { System.out.println("被代理类方法开始执行"); } } class MyInvocationHandler implements InvocationHandler{ Object obj;// 实现了接口的被代理类的对象的声明 // 1.给被代理的对象实例化 2.返回一个代理类的对象 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(); // 2.创建一个实现了InvacationHandler接口的类的对象 MyInvocationHandler handler=new MyInvocationHandler(); // 3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象 Object object=handler.blind(real); // 4.此时subject就是代理类的对象 Subject subject=(Subject)object; // 5.转到对InvocationHandler接口对实现类对invoke()方法的调用 subject.action(); // 再举一例 NikeClothFactory nikeClothFactory=new NikeClothFactory(); // proxyCloth即为代理类的对象 ClothFactory proxyCloth=(ClothFactory)handler.blind(nikeClothFactory); proxyCloth.productCloth(); } }