反射

反射

反射机制

初识反射

反射:指的是对象的反响处理。根据对象倒退类的组成

  • 在默认情况下,先要导入一个包,而后才能产生类的实例化对象,处理流程根据包名.类名找到类

  • 而这里的“反”就是对象来取得对象的来源信息,反射的核心类Class类(专门描述其他类的组成)

    • Objectlei中取得对象的class对象

      1
      public final native Class<?> getClass();
      • Class描述接口与类的组成,Class对象由JVM在第一次加载类的产生,并且全局唯一

      范例:

      1
      2
      3
      4
      5
      6
      public class mytest {
      public static void main(String[] args) throws ClassNotFoundException{
      Class<?> cls=Class.forName("java.util.Date");
      System.out.println(cls.getName());
      }
      }

在反射的世界中,看重的不再时一个对象,而是对象身后的组成(类,构造,普通,成员等)

取得任意类Class对象的三种方法:

  1. 调用对象 .getClass()取得Class对象,由Object类提供
  2. 类名调用 .class取得Class对象
  3. Class.forName(类全名称)取得Class对象
  • 在三中方法中只有第一种方法会产生类的实例化对象之外,其他两种均不会产生实例化对象。取得Class对象,可以通过反射实例化对象,在Class类中定义如下方法:

    1
    2
    public T newInstance()
    throws InstantiationException,IllegalAccessException

    范例:反射实例化对象

    1
    2
    3
    4
    5
    6
    7
    public class mytest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    Class<?> cls=Class.forName("java.util.Date");
    Object obj=cls.newInstance(); //实例化对象,等价于new java.util,Date()
    System.out.println(obj);
    }
    }

反射与工厂模式

  • 在传统的工厂模式中,每当我们增加一个接口的子类都需要去修改工厂类,为了解决该类问题,可以通过反射来处理,Class类可以使用newInstance()实例化对象,而Class.for通过Name()能够接收类名称。这样一来就避免了直接实例化(new)带来的问题,而是直接通过接收类名去实例化对象,避免了对工厂类的频繁修改。

    范例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    /**
    * 反射与工厂模式
    */
    package www.Dyson;
    interface IFruit{
    public void eat();
    }
    class Orange implements IFruit{
    @Override
    public void eat() {
    System.out.println("eat an orange");
    }
    }
    class Apple implements IFruit{
    @Override
    public void eat() {
    System.out.println("eat an apple");
    }
    }
    class fruitFactroy{
    //使用static修饰,当主方法中调用该方法通过反射实例化一个对象时
    //使用过静态方法调用的,所以getInstance方法必须也是静态方法,否则
    //会报无法从静态上下文中引用非静态方法的错误
    public static IFruit getInstance(String fruitName){
    IFruit iFruit=null;
    try {
    //通过.forName取得class对象
    Class<?> cls=Class.forName(fruitName);
    try {
    //通过反射取得实例化对象
    iFruit = (IFruit) cls.newInstance();
    } catch (InstantiationException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }
    return iFruit;
    }
    }
    public class ReflectAndFactory {
    public static void main(String[] args)throws Exception{
    IFruit iFruit=fruitFactroy.getInstance("www.Dyson.Apple");
    iFruit.eat();
    }
    }

    在主方法中调用该方法通过反射实例化一个·对象,而主方法是一个静态方法,所以该方法也必须为静态方法。


反射与类操作

取得父类&父接口信息

  • 取得类的包名称:

    1
    public Package getPackage();
  • 取得父类的Class对象:

    1
    public native Class<? super T> getSuperclass();
  • 取得实现的父接口:

    1
    public Class<?>[] getInterfaces();

通过反射可以取得类结构上的所有关键信息

以上所有父类:只能取得子类直接继承的父类

反射与构造方法 – Constructor(描述类构造方法信息)只能取得本类中的构造方法,与集成无关

取得类中指定参数构造方法
  • 取得类中权限只有public的指定构造方法

    1
    public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
  • 取得类中任意权限的指定构造方法

    1
    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
取的类中所有构造方法 —— 重要 ——
  • 取得类中所有权限为public的构造方法

    1
    public Constructor<?>[] getConstructors() throws SecurityException
  • 取得类中所有权限构造方法

    1
    public Constructor<?>[] getDeclaredConstructors() throws SecurityException

Class类的newInstance()实际调用的是类中的无参构造。若类中没有无参构造或者权限不是public,则无法使用Class类调用!!!

  • Constructor类的如下方法

    1
    public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException,               IllegalArgumentException, InvocationTargetException
    • 如果类中没有无参构造,则只能调用Constructor类提供的newInstance方法使用有参构造来实例化对象

    范例:通过Constructor类实例化对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package Dyson;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    class Person_p{
    private String name="Dyson";
    private int age=18;
    public Person_p(String name, int age) {
    this.name = name;
    this.age = age;
    }
    @Override
    public String toString() {
    return "Person{" +
    "name='" + name + '\'' +
    ", age=" + age +
    '}';
    }
    }
    public class mytest {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
    Class<?> cls=Person_p.class;
    Constructor<?> con=cls.getConstructor(String.class,int.class);
    System.out.println(con.newInstance("Dyson",18));
    }
    }

反射调用普通方法(核心 – Method)—— 重要 ——

取得类中指定名称与参数的普通方法
1
public Method getMethod(String name,Class<?>... parameterTypes)
1
public Method getDeclaredMethod(String name,Class<?>... parmeterTypes)
取得类中所有普通方法
  • 取得本类以及父类所有权限为public的普通方法(包含静态方法)

    1
    public Method[] getmethods() throws SecurityException
  • 取得本类中所有方法(包含private方法)

    1
    public Method[] getDeclaredmethods() throws SecurityException
  • 调用 – 通过invoke可以取得设置属性信息,不再局限于某一个具体的对象,而是可以通过Object类型进行对所有类的方法调用。

    1
    2
    3
    4
    5
    6
    /**
    *反射调用普通对象
    *obj类的实例化对象
    *args普通方法参数
    */
    public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException

反射调用类中属性(Field)

取得类中指定名称属性
1
public Field getField(String name)     父类
1
public Field getDeclaredField(String name)     本类
取得类中所有属性 – 同Meyhod一样
1
public Field[] getFields throws SecurityException()     父类
1
public Field[] getDeclaredFields throws SecurityException()     本类
设置与取得值 – 属性值为public
  • 设置属性值

    1
    2
    3
    4
    5
    /**
    *obj类的实例化对象
    *value所有设置的值
    */
    public void set(Object obj, Object value)
  • 取得属性值

    1
    2
    3
    4
    /**
    *obj类的实例化对象
    */
    public Object get(Object obj)
  • 取得属性值

    1
    public Class<?> getType()
动态破坏封装(反射特性)可以处理private权限的属性 – 只是在一次JVM进程中破坏,且只能通过反射来调用
  • Constuctor,Method,Field类都继承AccessibleObject类,此类中只有一个破坏的方法

    1
    public void setAccessible(boolean flag) throws SecurityException

    范例:通过反射操作private权限的属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    package Dyson;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    class Person_p{
    private String name;
    }
    public class mytest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
    Class<?> cls=Class.forName("Dyson.Person_p");
    //实例化对象
    Object obj=cls.newInstance();
    //取得要操纵的属性
    Field field=cls.getDeclaredField("name");
    //破坏封装
    field.setAccessible(true);
    //设置属性内容
    field.set(obj,"Dyson");
    //取得属性
    System.out.println(field.get(obj));
    }
    }