zoukankan      html  css  js  c++  java
  • java 的反射机制

    一:介绍

    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     @Override
    32     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         //通过类的加载器获得class
    23         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         //ExterSionClassLoader
    11         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<T>{
    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<String> 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     @Override
    49     public String toString() {
    50         return "Person [name=" + name + ", age=" + age + "]";
    51     }
    52     @Override
    53     public int compareTo(Object o) {
    54         // TODO Auto-generated method stub
    55         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<f.length;i++){
    16             System.out.println(f[i].getName());
    17         }
    18     }
    19     /**
    20      * getDeclaredFields():获取运行时类本身声明的所有的属性
    21      */
    22     public static void get2(){
    23         Class clazz=Person.class;
    24         Field[] f=clazz.getDeclaredFields();
    25         for(Field ff:f){
    26             System.out.println(ff.getName());
    27         }
    28     }
    29 }

    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+"	");
    23             
    24             //属性类型
    25             Class type=ff.getType();
    26             System.out.print(type.getName()+"	");
    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          * 属性权限为public
    10          */
    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          * 属性权限为private
    22          */
    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          * 属性的权限为默认default
    31          * 这个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,所以打印为null
    13         
    14         Method m2 = clazz.getMethod("toString");
    15         Object returnVal1 = m2.invoke(p); //因为返回值为string,所以这样调用不会有什么现象
    16         System.out.println(returnVal1);   //没有现象,所以打印就是打印返回值
    17                 
    18         /**
    19          * private
    20          * 同时,这是带参数的函数
    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         @Test
    10         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         @Test
    20         public void test5(){
    21             Class clazz = Person.class;
    22             Package pack = clazz.getPackage();
    23             System.out.println(pack);
    24         }
    25         
    26         //4.获取实现的接口
    27         @Test
    28         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         @Test
    38         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         @Test
    50         public void test2(){
    51             Class clazz = Person.class;
    52             Type type1 = clazz.getGenericSuperclass();
    53             System.out.println(type1);
    54         }
    55         
    56         //1.获取运行时类的父类
    57         @Test
    58         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     @Override
    13     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     @Override
    30     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 //动态代理都要实现接口InvocationHandler
    21 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(), obj
    27                 .getClass().getInterfaces(), this);
    28     }
    29     
    30     //当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
    31     @Override
    32     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。

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

      

      

  • 相关阅读:
    什么样的代码称得上是好代码?
    九年程序人生 总结分享
    Docker入门 第一课 --.Net Core 使用Docker全程记录
    阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
    Visual studio 2015 Community 安装过程中遇到问题的终极解决
    Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
    java 进销存 库存管理 销售报表 商户管理 springmvc SSM crm 项目
    Leetcode名企之路
    24. 两两交换链表中的节点
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/juncaoit/p/7029184.html
Copyright © 2011-2022 走看看