Java反射原理

1、反射

类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。

字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。

通过Class类、Method类、Field类等等类可以得到这个类型的一些信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术

1、Java当中,所有事物都是对像,这个所有对像就是万物,而要想抓住这些事物的灵魂就是反射要做的事。

正所谓:射其肉七天可愈,射其魄生不如死。

不是《让子弹飞》上有句话是这样说的吗:诛人诛心。正是这个意思。

2、通过反射我们可以分析类有什么、能做什么?而所有这一切我们只需要知道一件事,就是类的名字是什么。

3、反射更像是一个算命先生,但他不是算而是分析。

4、反射甚至可以通过调用私有的构造来构造一个对像

1.1 获取Class对象的三种方式

Java中有一个Class类用于代表某一个类的字节码。

Java提供了三种方式获取类的字节码

   forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装

   类名.class

   对象.getClass()

/**

    * 加载类的字节码的3种方式

    * @throws Exception

    * */

   public void test1() throws Exception {

      // 方式一

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      // 方式二

      Class clazz2 = Person.class;

      // 方式三

      Person p1 = new Person();

      Class clazz3 = p1.getClass();

   }

1.2 通过Class类获取类型的一些信息

1. getName()类的名称(全名,全限定名)

2 getSimpleName()类的的简单名称(不带包名)

3. getModifiers(); 类的的修饰符

4.创建对象

   无参数构造创建对象

   newInstance()

5. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例

    Constructor<T> getConstructor(Class<?>... parameterTypes)

   

/**

    * 通过Class对象获取类的一些信息

    *

    * @throws Exception

    * */

   private static void test2() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      // 获取类的名称

      String name = clazz1.getName();

      System.out.println(name); // cn.test.gz.reflect.Person

      // 获取类的简单名称

      System.out.println(clazz1.getSimpleName()); // Person

      // 获取类的修饰符

      int modifiers = clazz1.getModifiers();

      System.out.println(modifiers);

      // 构建对象(默认调用无参数构造.)

      Object ins = clazz1.newInstance();

      Person p = (Person) ins;

      System.out.println(p); // cn.test.gz.reflect.Person@c17164

      // 获取指定参数的构造函数

      Constructor<?> con = clazz1.getConstructor(String.class, int.class);

      // 使用Constructor创建对象.

      Object p1 = con.newInstance("jack", 28);

      System.out.println(((Person) p1).getName());

   }

1.3 通过Class类获取类型中的方法的信息

1.获取公共方法包括继承的

   getMethods()返回一个数组,元素类型是Method

2.获取指定参数的公共方法

   getMethod("setName", String.class);

3.获得所有的方法,包括私有

   Method[] getDeclaredMethods() 

4.获得指定参数的方法,包括私有

   Method getDeclaredMethod(String name, Class<?>... parameterTypes)

   /**

    * 获取公有方法.

    * @throws Exception

    * */

   private static void test3() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      // 1.获取非私用方法(包括父类继承的方法)

      Method[] methods = clazz1.getMethods();

      System.out.println(methods.length);

      for (Method m : methods) {

          // System.out.println(m.getName());

          if ("eat".equals(m.getName())) {

             m.invoke(clazz1.newInstance(), null);

          }

      }

   }

/**

    * 获取指定方法签名的方法

    *

    * @throws Exception

    * */

   private static void test4() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      // 获取指定名称的函数

      Method method1 = clazz1.getMethod("eat", null);

      method1.invoke(new Person(), null);

   }

/**

    * 获取指定方法名且有参数的方法

    *

    * @throws Exception

    * */

   private static void test5() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      Method method = clazz1.getMethod("eat", String.class);

      method.invoke(new Person(), "包子");

   }

   /**

    * 获取指定方法名,参数列表为空的方法.

    *

    * @throws Exception

    * */

   private static void test4() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      // 获取指定名称的函数

      Method method1 = clazz1.getMethod("eat", null);

      method1.invoke(new Person(), null);

   }

/**

    * 反射静态方法

    * @throws Exception

    * */

   private static void test7() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      Method method = clazz1.getMethod("play", null);

      method.invoke(null, null);

   }

   /**

    * 访问私有方法 暴力反射

    * @throws Exception

    * */

   private static void test6() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      Method method = clazz1.getDeclaredMethod("movie", String.class);

      method.setAccessible(true);

      method.invoke(new Person(), "苍老师");

   }

1.4 通过Class类获取类型中的字段的信息

1.获取公共字段

   Field[] getFields() 

2.获取指定参数的公共字段

   Field getField(String name) 

3.获取所有的字段

   Field[] getDeclaredFields() 

4.获取指定参数的字段,包括私用

   Field getDeclaredField(String name) 

/**

    * 获取公有的字段

    * */

   private static void test8() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      Field[] fields = clazz1.getFields();

      Person p = new Person();

      System.out.println(fields.length);

      for (Field f : fields) {

          System.out.println(f.getName());

          if ("name".equals(f.getName())) {

             System.out.println(f.getType().getName());

             f.set(p, "jack");

          }

      }

      System.out.println(p.getName());

   }

/**

    * 获取私有的字段

    * @throws Exception

    * */

   private static void test9() throws Exception {

      Class clazz1 = Class.forName("cn.test.gz.reflect.Person");

      Field field = clazz1.getDeclaredField("age");

      System.out.println(field.getName());

      field.setAccessible(true);

      Person p = new Person();

      field.set(p, 100);

      System.out.println(p.getAge());

   }

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棉花糖老丫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值