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。

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

      

      

  • 相关阅读:
    linux追加中文字库,解决imagemagick 中文乱码的问题。
    laravel 学习
    postman post 数据格式
    PHP5各个版本的新功能和新特性总结
    laravel 自定义常量方法
    微信服务号获得openid 跟用户信息
    【转】solr deltaImportQuery deltaQuery parentDeltaQuery 用法规则
    Shell
    [spring] org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sessionFactory' is d .
    [transaction] org.hibernate.HibernateException: createQuery is not valid without active transaction
  • 原文地址:https://www.cnblogs.com/juncaoit/p/7029184.html
Copyright © 2011-2022 走看看