Java反射机制


一、反射概述

1、反射简介

在一个程序加载完类后,在堆内存的方法区内就产生了一个Class类型的对象一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。可以通过这个对象看到对应类的内部结构,所以称之为反射。

2、反射的作用

反射机制允许程序在执行期间借助于Refletion API获取任何类的内部信息,并能够直接操作任意对象的内部属性和方法。

二、Class类

1、Class类介绍

在 Object 类中定义了以下的方法,此方法将被所有子类继承:

	public final Class getClass()

以上的方法返回值的类型是一个 Class 类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即可以通过对象反射求出类的名称。

  • Class本身也是一个类
  • Class对象只能由系统建立
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件

2、获取Class类的实例的四种方法

1)对象获取Class类

String str="www.baidu.com";
Class clazz=str.getClass();

2)类的属性获取Class类

Class clazz=String.class;

3)全类名获取Class类

Class clazz=Class.forName("java.lang.String");

4)类加载器获取Class类(了解)

ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);

3、Class对象应用

3.1 创建类的对象

通过Class对象获取对应的构造器方法,然后用构造器方法创建对象:

    //1、根据全类名获取对应的Class对象
    String name = "java.lang.String";
    Class clazz=null;
    clazz = Class.forName(name);
    //2、调用指定参数结构的构造器,生成Constructor的实例
    Constructor con = clazz.getConstructor(String.class);

    //3、通过Constructor的实例创建对应类的对象,并初始化类的属性
    String s = (String) con.newInstance("我是ssl");
    System.out.println(s);

3.2 构造器相关应用

    //获取全部public的构造器
    Constructor[] constructors = clazz.getConstructors();

    //获取全部的构造器(包括private类型的)
    Constructor[] declaredConstructors = clazz.getDeclaredConstructors();

    Constructor constructor = constructors[0];
    //获取单个构造器的修饰符,例如public、private
    constructor.getModifiers();
    //获取单个构造器的方法名称
    String name = constructor.getName();
    //获取单个构造器的参数类型
    Class[] parameterTypes = constructor.getParameterTypes();

3.3 类中方法相关应用

    Class clazz = People.class;

    People people=new People();
    Class clazz1 = people.getClass();

    Class clazz2 = Class.forName("People");

    //获取Class对象所表示的类中定义的所有方法(包括private类型方法)
    Method[] declaredMethods = clazz.getDeclaredMethods();

    //获取Class对象所表示的类中声明为public的方法
    Method[] methods = clazz.getMethods();

    Method method = methods[0];
    //获取单个方法的返回值
    Class<?> returnType = method.getReturnType();
    //获取单个方法全部参数
    Class<?>[] parameterTypes = method.getParameterTypes();
    //获取单个方法的修饰符
    int modifiers = method.getModifiers();
    //获取单个方法的所有异常信息
    Class<?>[] exceptionTypes = method.getExceptionTypes();

3.4 类中字段相关应用

    Class clazz = People.class;

    //获取Class对象所表示类中所有的字段
    Field[] declaredFields = clazz.getDeclaredFields();
    //获取Class对象所表示类中所有的public类型的字段
    Field[] fields = clazz.getFields();

    Field field = fields[0];
    //获取单个字段的修饰符
    int modifiers = field.getModifiers();
    //获取单个字段的属性类型,例如int、String
    Class type = field.getType();
    //获取单个字段的名称
    String name = field.getName();

4、Class对象调用运行时类的指定结构

4.1 调用指定的字段

    Class clazz = People.class;

    //创建对象
    People people = (People) clazz.newInstance();

    //获取name这个字段
    Field name = clazz.getDeclaredField("name");
    //设置属性是可访问的
    name.setAccessible(true);

    //获取people这个对象的name字段的值
    Object o = name.get(people);
    System.out.println(o);

    //把people这个对象的name字段进行赋值
    name.set(people,"ssl");
    System.out.println(people.toString());

4.2 调用指定的方法

需要注意的是:如果调用的方法是static方法,传入的对象可以为null

    Class clazz = People.class;

    //创建对象
    People people = (People) clazz.newInstance();

    //获取people对象里的show这个方法,它没有参数
    Method method = clazz.getDeclaredMethod("show");
    //设置方法是可访问的
    method.setAccessible(true);

    //调用获取的方法
    Object result = method.invoke(people);
    System.out.println(result);

    //调用静态方法,可以省略对象名称,通过class对象直接调用即可
    Method show_static = clazz.getDeclaredMethod("show_static");
    show_static.setAccessible(true);
    //调用的方法是static类型的,不需要对象,所以可以传入null
    Object invoke = show_static.invoke(null);
    System.out.println(invoke);

4.3 调用指定的构造器

    Class clazz = People.class;

    //创建对象
    People people = (People) clazz.newInstance();

    //获取people对象里的带有单个参数的构造器
    Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
    //设置构造器是可访问的
    declaredConstructor.setAccessible(true);

    //通过获取的构造器创建对象
    People new_people = (People) declaredConstructor.newInstance("SSL");
    System.out.println(new_people.toString());

4.4 获取相关泛型

获取运行时类的父类:

    Class clazz = People.class;

    //获取运行时类的父类
    Class superclass = clazz.getSuperclass();
    System.out.println(superclass.getName();

获取带泛型的父类和泛型的类型:

    //假设People类继承了Person<String>
    Class clazz = People.class;

    //获取clazz表示的类的带泛型的父类,返回值是Person<String>
    Type genericSuperclass = clazz.getGenericSuperclass();
    
    //获取这个带泛型的父类的泛型类型
    ParameterizedType paramType = (ParameterizedType) genericSuperclass;
    Type[] actualTypeArguments = paramType.getActualTypeArguments();
    //这里只有一个泛型为String,返回值是java.lang.String
    String typeName = actualTypeArguments[0].getTypeName();
    //也可以如下方式
    String name = ((Class) actualTypeArguments[0]).getName();

4.5 获取相关注解

自定义注解类:

	@Target(ElementType.TYPE)
	@Retention(RetentionPolicy.RUNTIME)
	@interface Tablemi{
	    String value();
	}
	@Target(ElementType.FIELD)
	@Retention(RetentionPolicy.RUNTIME)
	@interface Fieldmi{
	    String name();
	    String type();
	    int length();
	}

定义实体类:

@Tablemi("mi")
class Student2 {
    @Fieldmi(name = "id", type = "int", length = 10)
    private int id;
    @Fieldmi(name = "age", type = "int", length = 3)
    private int age;
    @Fieldmi(name = "name", type = "varchar", length = 5)
    private String name;

    public Student2() {
    }

    public Student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}//并提供get和set方法

获取类/字段/方法的所有注解:

    Class c1 = Class.forName("Student2");
    //通过反射获取注解
    Annotation[] annotations = c1.getAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println(annotation);
    }

获取对应的某个注解:

    //获的注解的value值
    Tablemi tablemi = (Tablemi)c1.getAnnotation(Tablemi.class);
    String value = tablemi.value();
    System.out.println(value);

    //获得字段指定的注解
    Field field = c1.getDeclaredField("id");
    Fieldmi fieldmi = field.getAnnotation(Fieldmi.class);
    System.out.println(fieldmi.name());
    System.out.println(fieldmi.type());
    System.out.println(fieldmi.length());

判断注解是否存在:

    boolean annotationPresent = c1.isAnnotationPresent(Tablemi.class);
    System.out.println(annotationPresent);

4.6 其他API

方法说明
public Class<?>[] getInterfaces()获取此对象表示的类实现的接口
public Class<? Super T> getSuperclass()获取此对象表示的类的父类的Class
Package getPackage() 获取此对象表示的类所在的包

5、关于setAccessible方法的使用

方法、字段、构造器都有setAccessible()方法。
setAccessible用于启动和禁用访问安全检查的开关。
参数值为true表示反射的对象在使用的时候应该取消Java语言的访问检查。优点是:提高反射的效率,如果代码中必须使用反射,而该句代码需要频繁的被调用,那么就最好设置为true;第二是使得原本无法访问的私有成员、方法、构造器也可以访问。
参数值为false时则表示反射的对象应该实施Java语言访问检查,如果为private等则不可以被访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值