zoukankan      html  css  js  c++  java
  • 反射

    一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖(反射)出类的各个组成部分。
    本人在下面的反射例子中以注释的形式把所理解的东西写了出来

    Person类:

     1 import java.util.List;
     2 
     3 public class Person {
     4 
     5     /*
     6      * 1.构造方法
     7      */
     8     //无参的
     9     public Person(){
    10         System.out.println("无参的构造方法!");
    11     }
    12     //一个参数,类型为String的
    13     public Person(String name){
    14         System.out.println("name:" + name);
    15     }
    16     //一个参数,类型为int的,且为私有的
    17     private Person(int age){
    18         System.out.println("age:" + age);
    19     }
    20     //参数为两个参数
    21     public Person(String name, int age){
    22         System.out.println(name + "的年龄:" + age + "岁");
    23     }
    24     //参数为List的
    25     public Person(List list){
    26         System.out.println("list:" + list);
    27     }
    28     
    29     /*
    30      * 2.普通方法
    31      */
    32     //1、无参
    33     public void methodTest(){
    34         System.out.println("这是无参的普通方法!");
    35     }
    36     
    37     //2、一个参数
    38     public void methodTest(String name){
    39         System.out.println("名字:" + name);
    40     }
    41     //3、一个参数私有的
    42     private void methodTest(int age){
    43         System.out.println("年龄:" + age);
    44     }
    45     //4、两个参数静态的
    46     public static void methodTest(String name, int age){
    47         System.out.println(name + "的年龄:" + age);
    48     }
    49     //5、main方法
    50     public static void main(String[] args) {
    51         System.out.println("main方法:");
    52     }
    53     
    54     /*
    55      * 3.字段
    56      */
    57     public String name = "张三";
    58     private int age = 25;
    59     private static String password = "PaSs1111";
    60 }

    测试代码:

      1 import java.lang.reflect.Constructor;
      2 import java.lang.reflect.Field;
      3 import java.lang.reflect.InvocationTargetException;
      4 import java.lang.reflect.Method;
      5 import java.util.ArrayList;
      6 import java.util.List;
      7 
      8 import org.junit.Test;
      9 
     10 public class ReflectTest {
     11 
     12     /**
     13      * @功能:反射
     14      * @介绍:
     15      *         clazz1.getConstructor()中的参数是可变参数,
     16      *     且用clazz1.getConstructor()只能反射出public型的,private反射不到
     17      *     如果想要得到private的构造方法,则需要用clazz.getDeclaredConstructor()来反射private的构造函数
     18      * @日期:2013-10-22
     19      */
     20 
     21     /*
     22      * 1.构造方法反射
     23      */
     24     @Test
     25     public void test1() throws Exception{
     26         //加载类(方式一) 参数中类名要全称
     27         Class clazz1 = Class.forName("cn.itcast.reflect.Person");
     28         //加载类(方式二)  ==> 实例化的时候构造方法直接运行
     29 //        Class clazz2 = new Person().getClass();
     30         //加载类(方式三)
     31 //        Class clazz3 = Person.class;
     32         //反射无参的构造方法,null表示无参
     33         Constructor c = clazz1.getConstructor(null);
     34         //new一个对象(正常情况下返回的是Object型的,这里强转为Person)
     35         Person p = (Person) c.newInstance();
     36     }
     37     
     38     @Test
     39     public void test2() throws Exception{
     40         //加载类
     41         Class clazz = Class.forName("cn.itcast.reflect.Person");
     42         //解剖(反射)出参数为String的构造方法(String.class)
     43         Constructor c = clazz.getConstructor(String.class);
     44         c.newInstance("张三");
     45     }
     46     
     47     @Test
     48     public void test3() throws Exception{
     49         //加载类
     50         Class clazz = Class.forName("cn.itcast.reflect.Person");
     51         //解剖(反射)出参数为int的构造方法(int.class)
     52         /*
     53          * 因为此时的构造方法为private的,所以正常的clazz.getConstructor(),不能反射出来
     54          * 此时就要用clazz.getDeclaredConstructor()来反射private的构造函数
     55          * 但解剖出来的构造方法不能直接new一个新的对象,还得能过c.setAccessible(true)修改一下属性(暴力反射)
     56          * ,这时才能进行new新对象,和正常的反射一样了
     57          */
     58         Constructor c = clazz.getDeclaredConstructor(int.class);
     59         //打开访问权限
     60         c.setAccessible(true);
     61         c.newInstance(25);
     62     }
     63     
     64     @Test
     65     public void test4() throws Exception{
     66         //加载类
     67         Class clazz = Class.forName("cn.itcast.reflect.Person");
     68         //反射方法
     69         Constructor c = clazz.getConstructor(String.class,int.class);
     70         //new
     71         c.newInstance("李四",25);
     72     }
     73     
     74     @Test
     75     public void test5() throws Exception{
     76         //加载类
     77         Class clazz = Class.forName("cn.itcast.reflect.Person");
     78         //反射方法
     79         Constructor c = clazz.getConstructor(List.class);
     80         //new
     81         List list = new ArrayList();
     82         list.add("zhangsan");
     83         list.add("lisi");
     84         list.add("wangwu");
     85         list.add("zhaoliu");
     86         c.newInstance(list);
     87     }
     88     
     89     /*
     90      * 2.普通方法反射
     91      */
     92     @Test
     93     public void test6() throws Exception{
     94         Person p = new Person();
     95         //加载类
     96         Class clazz = Class.forName("cn.itcast.reflect.Person");
     97         
     98         /*
     99          * 反射方法【clazz.getMethod("methodTest", null) 第一个参数为:方法名;第二个参数为:方法入参的类型】
    100          * 这里方法入参为空,所以用null表示参数类型
    101          */
    102         Method method = clazz.getMethod("methodTest", null);
    103         //method.invoke(p, null) 第一个参数要传一个对象,第二个为所反射的方法入参
    104         method.invoke(p, null);
    105     }
    106     
    107     @Test
    108     public void test7() throws Exception{
    109         Person p = new Person();
    110         //加载类
    111         Class clazz = Class.forName("cn.itcast.reflect.Person");
    112         //反射
    113         Method method = clazz.getMethod("methodTest", String.class);
    114         //
    115         method.invoke(p, "张三");
    116     }
    117     
    118     @Test
    119     public void test8() throws Exception{
    120         Person p = new Person();
    121         //加载类
    122         Class clazz = Class.forName("cn.itcast.reflect.Person");
    123         //私有的方法要用getDeclaredMethod来反射获取
    124         Method method = clazz.getDeclaredMethod("methodTest", int.class);
    125         //反射出来的方法此时还是private的,要强制打开访问权限
    126         method.setAccessible(true);
    127         //
    128         method.invoke(p, 25);
    129     }
    130     
    131     @Test
    132     public void test9() throws Exception{
    133         //加载类
    134         Class clazz = Class.forName("cn.itcast.reflect.Person");
    135         //反射
    136         Method method = clazz.getMethod("methodTest", String.class, int.class);
    137         /*
    138          * 静态的可以不传对象,为:null即可
    139          * (第一个参数为传对象的位置,后边的参数都是把反射方法的入参,invoke的“第二个参数”即为可变参数)
    140          */
    141         method.invoke(null, "李四", 25);
    142     }
    143     
    144     @Test
    145     public void test10() throws Exception{
    146         //加载类
    147         Class clazz = Class.forName("cn.itcast.reflect.Person");
    148         Method method = clazz.getMethod("main", String[].class);
    149         //main方法也是个静态方法
    150         /*
    151          * 关于下边注释的部分,是不可以用的,因为main方法中的参数为String[] args,是一个数组,在这里视为一个参数
    152          * 在jdk1.4之前,没有“可变参数”,到了1.5以后才有的可变参数
    153          * 那么,jdk1.4之前的method.invoke(String mehtodName, Object obj[])中
    154          * 第二个参数用一个数组Object obj[]来传参的,在invoke中会把这个数组拆解成为一个个对应的参数
    155          * 而jdk1.5是兼容jdk1.4的,所以,在jdk1.5中用数组来传参也可以,当然,它会把这个数组给拆解成几个参数
    156          * 因此,在调用main方法的时候,要在外围再加一个数组,具体如下【数组参数1/2】
    157          * 
    158          * 注:反射参数为数组的方法都要注意
    159          */
    160         //method.invoke(null, new String[]{"123","234"});
    161         //【数组参数1】
    162         method.invoke(null, new Object[]{new String[]{"1234","5678","9012"}});
    163         //【数组参数2】也可以这样(前边加一个Object可以欺骗一下程序,骗它为不是数组,其实传进去的确实为数组)
    164         method.invoke(null, (Object)new String[]{"1234","5678","9012"});
    165     }
    166     
    167     /*
    168      * 3.字段反射
    169      */
    170     
    171     @Test
    172     public void test11() throws Exception{
    173         Person p = new Person();
    174         //加载类
    175         Class clazz = Class.forName("cn.itcast.reflect.Person");
    176         //参数为字段名称
    177         Field field = clazz.getField("name");
    178         //获取字段值,传一个对象进去
    179         Object obj = field.get(p);
    180         //获取字段的类型
    181         Class type = field.getType();
    182         //如果字段类型为String,则打印数值
    183         if(type.equals(String.class)){
    184             String value = (String) obj;
    185             System.out.println(value);
    186         }
    187         //设置字段值,第一个参数传一个对象,第二个参数为修改的内容
    188         field.set(p, "李四");
    189         //打印一下,看看能不能通过反射来改变字段的值(结果:可以)
    190         System.out.println(p.name);
    191     }
    192     
    193     @Test
    194     public void test12() throws Exception{
    195         Person p = new Person();
    196         //加载类
    197         Class clazz = Class.forName("cn.itcast.reflect.Person");
    198         //
    199         Field field = clazz.getDeclaredField("age");
    200         //私有字段,修改访问权限
    201         field.setAccessible(true);
    202         System.out.println(field.get(p));
    203     }
    204     
    205     @Test
    206     public void test13() throws Exception{
    207         Person p = new Person();
    208         //加载类
    209         Class clazz = Class.forName("cn.itcast.reflect.Person");
    210         Field field = clazz.getDeclaredField("password");
    211         field.setAccessible(true);
    212         /*
    213          * 这里,password字段为私有且静态的字段,
    214          * 但静态字段不同于静态方法和静态构造方法,field.get(p)中必须传对象
    215          */
    216         System.out.println(field.get(p));
    217     }
    218 }
  • 相关阅读:
    Android Studio 快捷键
    Mac 下面,添加android adb命令(一般环境变量的添加方法)
    快速掌握 Android Studio 中 Gradle 的使用方法
    JAVA 十六进制与字符串的转换
    总结自己的Git常用命令
    Android性能优化典范---转
    【.NET Core微服务实战-统一身份认证】开篇及目录索引
    调用API修改Ocelot的配置文件
    VUE组件汇总
    Vue + GraphQL初试
  • 原文地址:https://www.cnblogs.com/zunpeng/p/3382854.html
Copyright © 2011-2022 走看看