Java基础 - 反射

10.反射

反射就是通过操作字节码文件来做两件事

  1. 创建对象
  2. 调用方法

对比硬编码效率会低一些,但是代码的灵活性大大提升

10.1 Class类 和 Class对象

运行Java程序,就是解析并且执行字节码文件,而字节码加载到JVM时,Java就会使用面向对象的思想把加载过来的字节码文件(class)封装成对象
问题是这个字节码文件在Java中是谁的对象?

例如:

对象--> “123”,“aaa”,“hello”
能描述以上对象的类型在Java中是String类型,所以以上是String的对象
对象--> 123,100,200
能描述以上对象的类型在Java中是Integer类型,所以以上是Integer的对象

在Java中万物皆对象,也就是说String和Integer也是对象,那他们到底是谁的对象呢?

对象--> String,Integer
能描述以上两种对象的类型是什么呢? 
  1. Class类是描述如String.class Integer.class等对象的类

  2. Java中所有的类型都是Class的对象

  3. 类型相同, 它们的字节码对象也都是相同的

10.2 反射创建对象

  • 获取Class对象

    1. 直接使用类名.class获取字节码文件对象

    2. 使用对象的方法getClass()获取到对象的字节码文件对象

      这个方法是来自Object类

    3. 使用Class类的静态方法forName(全限定名);

       static Class forName(String className) 通过类的全限定名获取Class对象
      
  • 无参构造创建对象

      //1.获取类的字节码对象
      Class clazz = Class.forName("com.example.mu.myapplication.TestCl");
      //创建无参构造的对象
      TestCl instance = (TestCl) clazz.newInstance();
    
  • 构造器创建对象

    如果字节码对象不包含无参构造,你就要通过获取里面的构造器再通过操作构造器来创建对象

    1. 获取字节码对象中的构造器

      • 获取public修饰的构造器

          Constructor getConstructor(Class... parameterTypes)  返回一个构造器,parameterTypes为构造器参数的类型
        
          Constructor[] getConstructors() 获得构造器对象的数组
        
      • 获取任意的构造器,包括私有的

          Constructor getDeclaredConstructor(Class... parameterTypes)
        
          Constructor[] getDeclaredConstructors()
        
    2. 用构造器创建对象

           T newInstance(Object... initargs) Constructor的创建对象方法
      
    3. 示例代码

       Constructor con= clazz.getConstructor(String.class);
       Object obj = con.newInstance("一个参数"); //这里的参数是对应构造器的参数
      
       //无参构造
       con = clazz.getConstructor(null);
       Object o2 = con.newInstance(null);
      
       //私有构造器
       con = clazz.getDeclaredConstructor(String.class);
       con.setAccessible(true);//私有的构造器需要设置访问权限,暴力反射
       con.newInstance("暴力反射");
      
  • 方法对象

    1. 获取字节码对象中的方法对象

      • 获取public修饰的方法,包括从父类继承的方法

          Method getMethod(String name, Class... parameterTypes)   获取指定的公共方法对象
          name:方法名    parameterTypes:方法参数的类型
        
          Method[] getMethods() 返回所有公共的方法对象的数组
        
      • 获取所有访问权限的方法,包括私有的,但不包括从父类继承的方法

          Method getDeclaredMethod(String name, Class... parameterTypes)
        
          Method[] getDeclaredMethods()
        
    2. Method对象调用方法

       Object invoke(Object obj, Object... var2)
       obj:调用该方法的对象    var2:该方法的实参
      
    3. 示例代码

       lass clazz = Class.forName("com.example.mu.myapplication.TestCl");
       TestCl instance = (TestCl) clazz.newInstance();
      
       //调用对象方法
       Method m1 = clazz.getMethod("setName", String.class);
       m1.invoke(instance,"我是谁");
      
       //不强制对象,调用对象的特有方法
       String s = "123";
       Method m2 = String.class.getMethod("length", null);
       Object o = m2.invoke(s, null);//invoke的返回值就是调用方法后的返回值
      
       //调用私有的方法
       Method work = clazz.getDeclaredMethod("work", null);
       work.setAccessible(true);
       work.invoke(instance,null);
      
       //调用静态方法
       Method m3 = clazz.getDeclaredMethod("lvup", null);
       //静态方法不需要对象来调用,因此传null
       m3.invoke(null,null);
      
  • 字段对象

    1. 获取Class对象中的Field对象

      • 获取public修饰的字段

          Field getField(String name)  name:字段名
        
          Field[] getFields() 返回包含所有公共字段的数组
        
      • 获取所有访问权限的字段

          Field getDeclaredField(String name)
        
          Field[] getDeclaredFields()
        
    2. Field对象,设置字段值和获取字段值

       Object get(Object obj)  获取指定对象上的此字段的值
      
       void set(Object obj, Object value) 将指定对象上的此字段设置为指定值
      
    3. 示例代码

       lass clazz = Class.forName("com.example.mu.myapplication.TestCl");
       TestCl instance = (TestCl) clazz.newInstance();
       Field name = clazz.getField("name");
       name.set(instance,"新名字");//设置值
       name.get(instance);//获取值
      
  • 其他

    int getModifiers() 获取修饰符

    Class对象,Method,Field都有的方法

      int modifiers = name.getModifiers();
      //将修饰符编码转出字符串
      System.out.println(Modifier.toString(modifiers));
    

你可能感兴趣的:(Java基础 - 反射)