反射

来源:互联网 发布:学java可以找什么工作 编辑:程序博客网 时间:2024/06/05 17:51

类加载器(了解)

  • 类的加载
    • 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
    • 加载

    就是指将class文件读入内存,并为之创建一个Class对象

    任何类被使用时系统都会建立一个Class对象。

  1. 连接

    验证是否有正确的内部结构,并和其他类协调一致

    准备负责为类的静态成员分配内存,并设置默认初始化值

    解析将类的二进制数据中的符号引用替换为直接引用

  1. 初始化就是我们以前讲过的初始化步骤
  2.  

类初始化时机

  • 创建类的实例
  • 访问类的静态变量,或者为静态变量赋值
  • 调用类的静态方法
  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

 

  • 类加载器
    • 负责将.class文件加载到内在中,并为之生成对应的Class对象。
    • 虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
  • 类加载器的组成
    • Bootstrap ClassLoader 根类加载器
    • Extension ClassLoader 扩展类加载器
    • Sysetm ClassLoader 系统类加载器

 

  • Bootstrap ClassLoader 根类加载器

l  也被称为引导类加载器,负责Java核心类的加载

l  比如System,String等。在JDKJRElib目录下rt.jar文件中

  • Extension ClassLoader 扩展类加载器

l  负责JRE的扩展目录中jar包的加载。

l  JDKJRElib目录下ext目录

  • Sysetm ClassLoader 系统类加载器

l  负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

 

 

/**

        * 1)系统提供给我们三个类加载器:

        *         BootStrap加载器:加载的jdk/jre/lib/rt.jar(开发的时候用的核心类)

        *         ExtClassLoad加载器:加载jdk/jre/lib/ext/*.jar (扩展包)

        *         AppClassLoad加载器:加载CLASSPATH中的jar包和class文件

        *

        *     MyClasLoader1加载器   MyClassLoader2加载器   都是AppClassLoad的子类

        *

        *        

        * 2) 这三个类加载器是树状结构.

        * 3) 类加载的过程:

        *     3.1 一个类A是有一个类加载器加载的,如果类A中使用到了类B,B也是由类A的类加载器加载

        * 4)委托机制:

        *     4.1 发起者类加载器去加载类的时候,先委托其父类加载如果还有父类加载器,则继续委托上去,直接没有父加载器为止。

        *         最顶层的类加载就需要真正地去加载指定类,如果在其类目录中找不到这个类,继续往下找,找到发起者类加载器为止!!!

        *

        * 委托机制的好处:

        *         可以让代码加载更加安全和高效!保证核心类的字节码只有一份在内存中。

        *    

        */

       //得到某个类被哪个类加载器加载

       //System.out.println(Demo1.class.getClassLoader().getClass());

      

       //这个类就由BootStrap加载

       //System.out.println(java.util.Date.class.getClassLoader());

      

       //查看某个类加载器树状结构

       ClassLoader classLoader = Demo1.class.getClassLoader();

       while(classLoader!=null){

           System.out.println(classLoader.getClass());

           classLoader = classLoader.getParent();

       }

       System.out.println(classLoader);  

      

 --------------------------------------------------------------------------------------------------------------------------------

1       反射

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

 

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

 

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

1.1.Class

1.1.1.  获取Class对象的三种方式

 

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

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

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

    类名.class

    对象.getClass()

 

/**

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

    * @throws Exception

    * */

   publicvoid test1() throws Exception {

      // 方式一

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

      // 方式二

      Class clazz2 = Person.class;

      // 方式三

      Person p1 = new Person();

      Class clazz3 = p1.getClass();

   }

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

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

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

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

4.创建对象

    无参数构造创建对象

    newInstance()

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

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

   

/**

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

    *

    * @throws Exception

    * */

   privatestaticvoidtest2() throws Exception {

 

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

      // 获取类的名称

      String name = clazz1.getName();

      System.out.println(name); // cn.itcast.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.itcast.gz.reflect.Person@c17164

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

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

      // 使用Constructor创建对象.

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

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

   }

 

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

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

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

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

    getMethod("setName", String.class);

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

    Method[] getDeclaredMethods() 

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

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

   /**

    * 获取公有方法.

    * @throws Exception

    * */

   privatestaticvoidtest3() throws Exception {

      Class clazz1 = Class.forName("cn.itcast.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

    * */

   privatestaticvoidtest4() throws Exception {

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

      // 获取指定名称的函数

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

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

   }

 

/**

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

    *

    * @throws Exception

    * */

   privatestaticvoidtest5() throws Exception {

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

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

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

   }

 

   /**

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

    *

    * @throws Exception

    * */

   privatestaticvoidtest4() throws Exception {

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

      // 获取指定名称的函数

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

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

   }

 

/**

    * 反射静态方法

    * @throws Exception

    * */

   privatestaticvoidtest7() throws Exception {

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

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

      method.invoke(nullnull);

   }

 

   /**

    * 访问私有方法暴力反射

    * @throws Exception

    * */

   privatestaticvoidtest6() throws Exception {

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

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

      method.setAccessible(true);

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

   }

 

 

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

1.获取公共字段

    Field[] getFields() 

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

    Field getField(String name) 

3.获取所有的字段

    Field[] getDeclaredFields() 

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

    Field getDeclaredField(String name) 

 

/**

    * 获取公有的字段

    * */

   privatestaticvoidtest8() throws Exception {

      Class clazz1 = Class.forName("cn.itcast.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

    * */

   privatestaticvoid test9() throws Exception {

      Class clazz1 = Class.forName("cn.itcast.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());

   }

 

0 0