博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 的反射机制
阅读量:6612 次
发布时间:2019-06-24

本文共 19533 字,大约阅读时间需要 65 分钟。

一:介绍

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 Creature
implements 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。

  在这篇文章中,这一段比我上面的程序写的更好理解:

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

你可能感兴趣的文章
LeetCode - 26. 删除排序数组中的重复项
查看>>
我的友情链接
查看>>
Windows 8.1核心版通过注册表启用Guest账号的局域网共享
查看>>
JQUEY学习第一天之可以编辑的表格
查看>>
[iOS Animation]-CALayer 显示动画 对图层树的动画
查看>>
电脑技术员联盟 Ghost XP Sp3 装机版 V5.8下载 .
查看>>
php 操作数组 (合并,拆分,追加,查找,删除等)
查看>>
Linux LVM逻辑卷配置过程详解
查看>>
(四)SpringBoot+SpringCloud —— Eureka注册中心的机制与配置
查看>>
关于IT服务管理的服务台
查看>>
[deviceone开发]-一个固定列,可以上下左右滑动的表格示例
查看>>
JavaScript细节----解密match(RegExp)
查看>>
Setting up Oozie high availability
查看>>
磁盘与文件系统
查看>>
我的友情链接
查看>>
[java]访问权限控制private/protected/public等
查看>>
批量添加域用户
查看>>
linux学习计划书
查看>>
Docker 初探(二) spring boot + docker
查看>>
使用secure CRT的SFTP在LINUX与WINDOWS下交换文件
查看>>