Java基础——反射

一、反射是什么

  反射机制是在运行状态中,

  对于任意一个类,都能够知道这个类的所有属性和方法;
  对于任意一个对象,都能够调用它的任意一个方法和属性;
  这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

二、反射能做什么

  • 在运行时判断任意一个对象所属的类;

  • 在运行时构造任意一个类的对象;

  • 在运行时判断任意一个类所具有的成员变量和方法;

  • 在运行时调用任意一个对象的方法;

  • 生成动态代理

  学习目标:

理解 Class 类

理解 Java 的类加载机制

学会使用 ClassLoader 进行类加载

理解反射的机制

掌握 Constructor、Method、Field 类的用法

理解并掌握动态代理

三、反射的API(怎么做)

  1.Class类

  在反射操作之前,必须理解的一个概念是Class类

    每一个类都对应有一个.class文件,.class文件被加载到内存后就对应一个运行时类,存放在缓存区。这个运行时类就是一个Class类的实例!

    每一个Class类的对象都对应着一个类的类型信息!

    更过详细的Class的讲解,强烈推荐:http://www.cnblogs.com/bethunebtj/p/4680532.html

  2.获取Class类实例的方式

    类名.class

Class clazz = Person.class;

    对象.getClass()

Class clazz = person.getClass();

    Class.forName("路径") 双击类名copy qualitied name获取路径

Class clazz = Class.forName("com.jiangbei.demo1.Person");

  // 当然,Class是可以添加泛型的

  只要类一加载,Class实例就被创建,你获取或者不获取,它就在那里,不离不弃。

   3.Class类常用方法

 操作的实体类如下:

package com.jiangbei.demo1.Entity;

/**
 * 人类
 * 作者: Administrator
 * 日期: 2017/9/19
 **/
public class Human {
    private double weight;

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }
    public void eat() {
        System.out.println("Human#eat()...");
    }
}
View Code
package com.jiangbei.demo1.Entity;

import java.io.Serializable;

/**
 * 男性类
 * 作者: Administrator
 * 日期: 2017/9/19
 **/
public class Man extends Human implements Serializable{
    private Integer age;
    private String name;
    public String hobby;

    public void show() {
        System.out.println("Man#show()...");
    }

    public String play(String type) throws Exception{
        System.out.println("Man#play()"+type);
        return "play"+type;
    }
    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
View Code

  创建运行时类的对象——newInstance()

  @Test
    public void test1() throws Exception {
        String className = "com.jiangbei.demo1.Person";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 创建运行时类的对象(通过无参公有构造器)
        Person p1 = (Person) clazz.newInstance();
    }

  通过反射调用类的完整结构——Field、Method、Constructor、SuperClass、interface、Annotation

                属性、方法、构造器、父类、接口、注解

  Field

    获取Field——获取单个指定的field与method,参见API

  @Test
    public void test1() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取属性,包括父类的(只能是public的)
        Field[] fields1 = clazz.getFields();
        for (Field field : fields1) {
            System.out.println(field);
        }
        // 获取属性,只能获取本身的属性(所有,只要声明了即有)
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }
        // 获取指定属性
        Field field = clazz.getDeclaredField("age");
        // System.out.println(field.getType().getName());

    }
View Code

  

    通过Field获取属性详细信息——当然还可以通过Field的set/get方法对特定对象属性进行读写操作,详见API(java.lang.reflect)

                  私有属性的访问问题需要先设置权限(field.setAccessible(true))

   @Test
    public void test2() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取属性,只能获取本身的属性(所有,只要声明了即有)
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
            // 获取属性权限修饰符(使用Modifier进行解码)
            int modifiers = field.getModifiers();
            System.out.println(Modifier.toString(modifiers));
            // 获取属性类型(这个类型也是一个Class实例)
            Class type = field.getType();
            System.out.println(type.getName());
            // 获取属性名(简称)
            System.out.println(field.getName());
        }

    }
View Code

  

  Method

    获取Method

   @Test
    public void test3() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取方法,包括直接父类和间接父类(所有公有的方法)
        Method[] methods = clazz.getMethods();
       /* for (Method method : methods) {
            System.out.println(method);
        }*/
        // 与属性类似,获取运行时类本身的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    }
View Code

  

  //列出部分方法

     通过Method获取详细信息——当然还可以通过invoke()进行方法的调用,可以参见API

    @Test
    public void test4() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 与属性类似,获取运行时类本身的所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            // 方法注解
            Annotation[] annotations = declaredMethod.getAnnotations();
            // 方法修饰符
            int modifiers = declaredMethod.getModifiers();
            System.out.print(Modifier.toString(modifiers));
            // 方法返回值
            Class returnType = declaredMethod.getReturnType();
            System.out.println(returnType.getName());
            // 方法名
            String name = declaredMethod.getName();
            System.out.print(name);
            // 形参列表(一般关心类型,形参名字不是重点)
            Class[] paraTypes = declaredMethod.getParameterTypes();
            // 抛出异常
            Class[] exceptionTypes = declaredMethod.getExceptionTypes();
            System.out.println();
        }
    }
View Code

   Constructor

    获取构造器——可以通过构造器的newInstance()来进行对象的构造

 @Test
    public void test5() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取构造器,本身公有的构造器
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName());
        }
    }
View Code

  Supperclass

    获取运行时父类(获取父类的泛型)

   @Test
    public void test6() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取父类
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass.getSimpleName());
        // 获取父类的泛型
        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        System.out.println(((Class)actualTypeArguments[0]).getName());
    }
View Code

  Interfaces

    获取实现的所有接口

@Test
    public void test7() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取接口
        Class[] interfaces = clazz.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface.getName());
        }
    }
View Code

  Package

    获取包

   @Test
    public void test7() throws Exception {
        String className = "com.jiangbei.demo1.Entity.Man";
        // 获取Class实例
        Class clazz = Class.forName(className);
        // 获取包
        Package aPackage = clazz.getPackage();
        System.out.println(aPackage.getName());
    }
View Code

  其它的获取内部类、类注解的不再赘述

   更多反射相关,参考这里

原文地址:https://www.cnblogs.com/jiangbei/p/6829755.html