一:介绍
1.大纲
#1
允许程序在执行期间,调用反射API取得任何类的内部信息,并且可以直接操作任何对象的内部属性和方法。
#2
学习反射,需要掌握的知识点:
*实例化class类
*获取类的完整结构
*通过反射调用类的属性和方法
*动态代理
2.涉及到的一些API
java.lang.Class 类
java.lang.reflect.Field 属性
java.lang.reflect.Method 方法
java.lang.reflect.Constructor 构造器
二:简单反射的小示例(可以直接看后面的内容)
1.新建要反射的类Person
这个要被反射的类中不含有父类,接口,注解等额外的部分,只是一个特别简单的可以被用来反射的类,用来做演示。
1 package demo2; 2 public class Person1 { 3 //这里为了说明反射,权限为public 4 public String name; 5 //这里为了说明反射,做对比,权限为private 6 private int age; 7 8 public Person1() { 9 super();10 }11 public Person1(String name) {12 super();13 this.name = name;14 }15 public Person1(int age) {16 super();17 this.age = age;18 }19 public String getName() {20 return name;21 }22 public void setName(String name) {23 this.name = name;24 }25 public int getAge() {26 return age;27 }28 public void setAge(int age) {29 this.age = age;30 }31 @Override32 public String toString() {33 return "Person1 [name=" + name + ", age=" + age + "]";34 }35 //两个普通的方法36 //不带参数的函数37 public void show(){38 System.out.println("this is person class");39 }40 //带参数的函数41 public void diaplay(String nation){42 System.out.println("contry is "+nation);43 }44 45 }
2.反射的测试
这个部分包括建立反射源
通过反射设置属性
通过反射调用方法函数
1 package demo2; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 6 public class Test1 { 7 8 public static void main(String[] args)throws Exception { 9 reflectMethod();10 }11 public static void reflectMethod()throws Exception{12 //产生对应的类13 Class clazz=Person1.class;14 Person1 p=(Person1)clazz.newInstance();15 System.out.println(p);16 System.out.println("-------------------------");17 18 //设置public权限的属性19 Field f=clazz.getField("name");20 f.set(p, "zhangsan");21 System.out.println(p);22 System.out.println("-------------------------");23 24 //设置private权限的属性25 Field f1=clazz.getDeclaredField("age");26 f1.setAccessible(true);//增加访问权限27 f1.set(p, 90);28 System.out.println(p);29 System.out.println("-------------------------");30 31 //调用不带参数的函数方法32 Method m=clazz.getMethod("show");33 m.invoke(p);34 System.out.println("-------------------------");35 36 //调用带参数的函数方法37 Method m1=clazz.getMethod("diaplay",String.class);38 m1.invoke(p, "China");39 }40 }
3.运行结果
-----------------------------------------------------------------------------------------------#反射重点#---------------------------------------------------------------------------------------------------
三:实现Class类的四种实现方式(所有反射的基础源头---class类的获取)
1.介绍四种方式获取要反射类的class文件
*用运行时类本身的.class获取
*通过运行时类的对象的获取
*以class的静态方法获取
*通过类的加载器获取
2.程序
1 package demo2; 2 3 import org.junit.Test; 4 5 public class Test2 { 6 @Test 7 public void classMethod() throws ClassNotFoundException{ 8 //通过类的class文件 9 Class c1=Person1.class;10 System.out.println(c1);11 12 //通过运行时类的对象获取class文件13 Person1 p=new Person1();14 Class c2=p.getClass();15 System.out.println(c2);16 17 //通过class的静态方法18 String name="demo2.Person1";19 Class c3=Class.forName(name);20 System.out.println(c3);21 22 //通过类的加载器获得class23 ClassLoader classLoader=this.getClass().getClassLoader();24 Class c4=classLoader.loadClass(name);25 System.out.println(c4);26 }27 28 }
3.运行结果
结果看到:四种方式都可以获得class类。
四:类的加载器(解释一下上面方式四中类的加载器,次要内容)
1.介绍
2.程序验证
1 package demo2; 2 import org.junit.Test; 3 public class Test3 { 4 @Test 5 public void show(){ 6 //systemClassLoader 7 ClassLoader c1=ClassLoader.getSystemClassLoader(); 8 System.out.println(c1); 9 10 //ExterSionClassLoader11 ClassLoader c2=c1.getParent();12 System.out.println(c2);13 14 //null(这一个类加载器不会被获取)15 ClassLoader c3=c2.getParent();16 System.out.println(c3);17 18 }19 }
3.运行结果
4.在方式四种使用的是哪一个加载器(程序验证)
1 package demo2; 2 import org.junit.Test; 3 public class Test4 { 4 @Test 5 public void method(){ 6 String name="demo2.Person1"; 7 ClassLoader classLoader=this.getClass().getClassLoader(); 8 System.out.println(classLoader); 9 }10 }
5.运行结果
五:创建运行时类对象(class文件的基础上)
1.要求
要反射的类中有空参的构造器(最好是这样)
构造器的权限为public
2.程序实现解释
1 package demo2;2 public class Test5 {3 public static void main(String[] args)throws Exception {4 Class c=Person1.class;5 Object obj=c.newInstance();6 Person1 p=(Person1)obj;7 System.out.println(p);8 }9 }
3.运行结果
六:重新构建复杂的即将被反射的类
1.构建复杂的类对象
包含:
*父类
*多接口
*注解
*内部类
*异常
首先是父类:
1 package com.at.java;2 3 public class Creature{4 public double weight;5 public void breath(){6 System.out.println("呼吸");7 }8 }
自定义接口:
1 package com.at.java;2 3 import java.io.Serializable;4 public interface MyInterface extends Serializable{5 6 }
自定义注解:
1 package com.at.java; 2 import static java.lang.annotation.ElementType.CONSTRUCTOR; 3 import static java.lang.annotation.ElementType.FIELD; 4 import static java.lang.annotation.ElementType.LOCAL_VARIABLE; 5 import static java.lang.annotation.ElementType.METHOD; 6 import static java.lang.annotation.ElementType.PARAMETER; 7 import static java.lang.annotation.ElementType.TYPE; 8 import java.lang.annotation.Retention; 9 import java.lang.annotation.RetentionPolicy;10 import java.lang.annotation.Target;11 12 @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})13 @Retention(RetentionPolicy.RUNTIME)14 public @interface MyAnnotation {15 String value();16 }
反射的类:
1 package com.at.java; 2 3 @MyAnnotation(value = "atguigu") 4 public class Person extends Creatureimplements Comparable,MyInterface{ 5 public String name; 6 private int age; 7 int id; 8 public Person() { 9 super();10 }11 public Person(String name) {12 super();13 this.name = name;14 }15 private Person(String name, int age) {16 super();17 this.name = name;18 this.age = age;19 }20 public String getName() {21 return name;22 }23 public void setName(String name) {24 this.name = name;25 }26 public int getAge() {27 return age;28 }29 public void setAge(int age) {30 this.age = age;31 }32 33 public int getId() {34 return id;35 }36 public void setId(int id) {37 this.id = id;38 }39 @MyAnnotation(value = "abc123")40 public void show(){41 System.out.println("this is person");42 }43 44 private Integer display(String nation,Integer i) throws Exception{45 System.out.println("国籍:" + nation);46 return i;47 }48 @Override49 public String toString() {50 return "Person [name=" + name + ", age=" + age + "]";51 }52 @Override53 public int compareTo(Object o) {54 // TODO Auto-generated method stub55 return 0;56 }57 58 public static void info(){59 System.out.println("信息");60 }61 62 class Bird{63 64 }65 66 }
七:获取以及调用类的属性
包括:
*所有属性的获取
*指定属性的调用
1.获取对应类运行时的属性
包括两种;
*getFields():只能获取到运行时类中及其父类中声明为public的属性
*getDeclaredFields():获取运行时类本身声明的所有的属性
1 package com.at.java; 2 import java.lang.reflect.Field; 3 public class Test1 { 4 public static void main(String[] args){ 5 get1(); 6 System.out.println("###################"); 7 get2(); 8 } 9 /**10 * getFields():只能获取到运行时类中及其父类中声明为public的属性11 */12 public static void get1(){13 Class clazz=Person.class;14 Field[] f=clazz.getFields();15 for(int i=0;i
2.运行结果
使用###进行将两种方式进行隔离。
3.获取对应类运行时的属性的各个部分的内容
主要包括:
*权限
*变量名
*变量名
1 package com.at.java; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Modifier; 5 6 public class Test2 { 7 8 public static void main(String[] args) { 9 get2();10 11 }12 /**13 * getDeclaredFields():获取运行时类本身声明的所有的属性的各个部分14 */15 public static void get2(){16 Class clazz=Person.class;17 Field[] f=clazz.getDeclaredFields();18 for(Field ff:f){19 //属性权限20 int num=ff.getModifiers();21 String str=Modifier.toString(num);22 System.out.print(str+"\t");23 24 //属性类型25 Class type=ff.getType();26 System.out.print(type.getName()+"\t");27 28 //属性变量名29 System.out.println(ff.getName());30 }31 }32 33 }
4.运行结果
5.调用设置指定属性
注意点事权限问题
1 package com.at.java; 2 3 import java.lang.reflect.Field; 4 5 public class Test6 { 6 public static void main(String[] args)throws Exception { 7 Class clazz=Person.class; 8 /** 9 * 属性权限为public10 */11 Field name = clazz.getField("name");12 Person p = (Person)clazz.newInstance();13 //将运行时类的指定的属性赋值14 name.set(p,"Jerry");15 System.out.println(p);16 //将运行时类的指定的属性赋值后再取出17 System.out.println("name="+name.get(p));18 19 System.out.println("########################");20 /**21 * 属性权限为private22 */23 Field age = clazz.getDeclaredField("age");24 age.setAccessible(true);//由于属性权限修饰符的限制,需要在操作前使得此属性可被操作。25 age.set(p,10);26 System.out.println(p);27 28 System.out.println("#######################");29 /**30 * 属性的权限为默认default31 * 这个set时不需要setAccessible(true)。32 */33 Field id = clazz.getDeclaredField("id");34 id.set(p,3);35 System.out.println(p);36 }37 }
6.运行结果
八:获取与调用对应类运行时的方法
包括两种:
*获取所有方法
*调用指定方法
1.获取对应类运行时的方法
包括两种:
*getMethods():获取运行时类及其父类中所有的声明为public的方法
*getDeclaredMethods():获取运行时类本身声明的所有的方法
1 package com.at.java; 2 import java.lang.reflect.Method; 3 public class Test3 { 4 public static void main(String[] args) { 5 get1(); 6 System.out.println("#############"); 7 get2(); 8 } 9 /**10 * getMethods():获取运行时类及其父类中所有的声明为public的方法11 */12 public static void get1(){13 Class clazz=Person.class;14 Method[] m=clazz.getMethods();15 for(Method mm: m){16 System.out.println(mm.getName());17 }18 }19 /**20 * getDeclaredMethods():获取运行时类本身声明的所有的方法21 */22 public static void get2(){23 Class clazz=Person.class;24 Method[] m=clazz.getDeclaredMethods();25 for(Method mm:m){26 System.out.println(mm.getName());27 }28 }29 }
2.运行结果
3.获取对应类运行时的方法的各个部分
包括:
*注解
*权限
*返回类型
*方法名
*参数列表
*异常类型
1 package com.at.java; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Modifier; 6 7 public class Test4 { 8 9 public static void main(String[] args) {10 get2();11 }12 /**13 * 注解 权限修饰符 返回值类型 方法名 形参列表 异常14 */15 public static void get2(){16 Class clazz = Person.class;17 Method[] m2 = clazz.getDeclaredMethods();18 for(Method m : m2){19 //1.注解20 Annotation[] ann = m.getAnnotations();21 for(Annotation a : ann){22 System.out.println(a);23 }24 25 //2.权限修饰符26 String str = Modifier.toString(m.getModifiers());27 System.out.print(str + " ");28 29 //3.返回值类型30 Class returnType = m.getReturnType();31 System.out.print(returnType.getName() + " ");32 33 //4.方法名34 System.out.print(m.getName() + " ");35 36 //5.形参列表37 System.out.print("(");38 Class[] params = m.getParameterTypes();39 for(int i = 0;i < params.length;i++){40 System.out.print(params[i].getName() + " args-" + i + " ");41 }42 System.out.print(")");43 44 //6.异常类型45 Class[] exps = m.getExceptionTypes();46 if(exps.length != 0){47 System.out.print("throws ");48 }49 for(int i = 0;i < exps.length;i++){50 System.out.print(exps[i].getName() + " ");51 }52 System.out.println();53 }54 }55 }
4.运行结果
5.调用指定方法
1 package com.at.java; 2 import java.lang.reflect.Method; 3 public class Test7 { 4 public static void main(String[] args) throws Exception{ 5 Class clazz = Person.class; 6 Person p = (Person)clazz.newInstance(); 7 /** 8 * public 9 */10 Method m1 = clazz.getMethod("show");11 Object returnVal = m1.invoke(p);12 System.out.println(returnVal); //因为返回值为void,所以打印为null13 14 Method m2 = clazz.getMethod("toString");15 Object returnVal1 = m2.invoke(p); //因为返回值为string,所以这样调用不会有什么现象16 System.out.println(returnVal1); //没有现象,所以打印就是打印返回值17 18 /**19 * private20 * 同时,这是带参数的函数21 */22 Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class);23 m4.setAccessible(true);24 Object value = m4.invoke(p,"CHN",10);25 System.out.println(value);26 27 /**28 * static 方法,单独提出来29 */30 Method m3 = clazz.getMethod("info");31 m3.invoke(Person.class);32 }33 }
6.运行结果
九:获取构造器
包括:
*所有的构造器
*调用指定的构造器
1.获取所有的构造器
1 package com.at.java; 2 import java.lang.reflect.Constructor; 3 public class Test8 { 4 public static void main(String[] args) throws Exception{ 5 String className = "com.at.java.Person"; 6 Class clazz = Class.forName(className); 7 /** 8 * 获取所有的构造器 9 */10 Constructor[] cons = clazz.getDeclaredConstructors();11 for(Constructor c : cons){12 System.out.println(c);13 }14 }15 }
2.运行结果
3.调用指定的构造器
1 package com.at.java; 2 import java.lang.reflect.Constructor; 3 public class Test9 { 4 public static void main(String[] args)throws Exception{ 5 String className = "com.at.java.Person"; 6 Class clazz = Class.forName(className); 7 /** 8 * 调用String,int的构造器 9 */10 Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);11 cons.setAccessible(true);12 Person p = (Person)cons.newInstance("罗伟",20);13 System.out.println(p);14 }15 }
4.运行结果
十:获取其他的内容(父类,接口,注解,包,)
1.程序
1 package com.at.java; 2 import java.lang.annotation.Annotation; 3 import java.lang.reflect.ParameterizedType; 4 import java.lang.reflect.Type; 5 import org.junit.Test; 6 7 public class Test10 { 8 //6.获取注解 9 @Test10 public void test6(){11 Class clazz = Person.class;12 Annotation[] anns = clazz.getAnnotations();13 for(Annotation a : anns){14 System.out.println(a);15 }16 }17 18 //5.获取所在的包19 @Test20 public void test5(){21 Class clazz = Person.class;22 Package pack = clazz.getPackage();23 System.out.println(pack);24 }25 26 //4.获取实现的接口27 @Test28 public void test4(){29 Class clazz = Person.class;30 Class[] interfaces = clazz.getInterfaces();31 for(Class i : interfaces){32 System.out.println(i);33 }34 }35 36 //3*.获取父类的泛型37 @Test38 public void test3(){39 Class clazz = Person.class;40 Type type1 = clazz.getGenericSuperclass();41 42 ParameterizedType param = (ParameterizedType)type1;43 Type[] ars = param.getActualTypeArguments();44 45 System.out.println(((Class)ars[0]).getName());46 }47 48 //2.获取带泛型的父类49 @Test50 public void test2(){51 Class clazz = Person.class;52 Type type1 = clazz.getGenericSuperclass();53 System.out.println(type1);54 }55 56 //1.获取运行时类的父类57 @Test58 public void test1(){59 Class clazz = Person.class;60 Class superClass = clazz.getSuperclass();61 System.out.println(superClass);62 }63 }
2.运行结果
十一:动态代理
1.静态代理
1 /** 2 * 静态代理模式 3 */ 4 package com.at.java1; 5 //接口 6 interface ClothFactory{ 7 void productCloth(); 8 } 9 10 //被代理类11 class NikeClothFactory implements ClothFactory{12 @Override13 public void productCloth() {14 System.out.println("Nike");15 } 16 public void productCloth2() {17 System.out.println("Nike2");18 }19 }20 21 //代理类22 class ProxyFactory implements ClothFactory{23 //引用24 ClothFactory cf;25 public ProxyFactory(ClothFactory cf){ //创建代理类的对象时,实际传入一个被代理类的对象26 this.cf = cf;27 }28 29 @Override30 public void productCloth() {31 System.out.println("一共$1000");32 cf.productCloth(); //实际在代理类中执行的还是被代理类的方法33 }34 35 }36 37 public class TestClothProduct {38 public static void main(String[] args) {39 NikeClothFactory nike = new NikeClothFactory();40 ProxyFactory proxy = new ProxyFactory(nike); //将被代理类传入代理类中41 proxy.productCloth();42 }43 }
2.运行结果
3.动态代理
1 /** 2 * 动态代理 3 */ 4 package com.at.java1; 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Proxy; 8 //接口 9 interface Subject {10 void action();11 }12 //被代理类13 class RealSubject implements Subject {14 public void action() {15 System.out.println("我是被代理类,记得要执行我哦!");16 }17 }18 19 //代理类20 //动态代理都要实现接口InvocationHandler21 class MyInvocationHandler implements InvocationHandler {22 Object obj;23 //①给被代理的对象实例化②返回一个代理类的对象24 public Object blind(Object obj) {25 this.obj = obj;26 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj27 .getClass().getInterfaces(), this);28 }29 30 //当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用31 @Override32 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { 33 Object returnVal = method.invoke(obj, args);34 return returnVal;35 }36 }37 38 public class TestProxy {39 public static void main(String[] args) {40 RealSubject real = new RealSubject();41 MyInvocationHandler handler = new MyInvocationHandler();42 //动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。43 Object obj = handler.blind(real);44 Subject sub = (Subject)obj;45 sub.action();46 }47 }
4.运行结果
十二:动态代理与静态代理的区别
2017.12.21,今天查看了一下他们之间的区别,在这篇文章中解释的挺好的,就没有重新整理,直接粘贴一下链接。
http://blog.csdn.net/hejingyuan6/article/details/36203505。
在这篇文章中,这一段比我上面的程序写的更好理解: