JAVA的重要机制——反射Reflection

有没有听说反射是Java中最强大的技术,很多优秀的开源框架都是通过反射完成的,那么你学会反射了吗?

JAVA反射机制概述

平常我们想调一个类中的方法时,类中用private修饰的变量、方法我们都调用不了,但是反射可以。

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

首先了解下什么是动态语言

  • 动态语言

    是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运 行时代码可以根据某些条件改变自身结构

  • 静态语言

    与动态语言相对应的,运行时结构不可变的语言就是静态语言。

Java不是动态语言,Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。

反射机制的概念

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

反射相关的主要API

  • java.lang.Class:代表一个类
  • java.lang.reflect.Method:代表类的方法
  • java.lang.reflect.Field:代表类的成员变量(类的属性)
  • java.lang.reflect.Constructor:代表类的构造方法

Class类的常用方法

ClassLoadergetClassLoader()返回类的类加载器。
static class<?>forName(String className)返回与给定字符串名称的类或接口相关联的 对象。
Annotation[]getAnnotations()返回此元素上 存在的注释。
ClassLoadergetClassLoader()返回类的类加载器。
Constructor<T>getConstructor(class<?>... parameterTypes)返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 函数。
Constructor<?>[]getConstructors()返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 对象。
Constructor<T>getDeclaredConstructor(类<?>... parameterTypes)返回一个 Constructor对象,该对象反映 Constructor对象表示的类或接口的指定 函数。
Constructor<?>[]getDeclaredConstructors()返回一个反映 Constructor对象表示的类声明的所有 Constructor对象的数组
FieldgetDeclaredField(String name)返回一个指定的运行时类中指定变量名的Field对象,包括公共,保护,默认访问和私有属性
Field[]getDeclaredFields()返回的数组 Field对象反映此表示的类或接口声明的所有字段 对象。
MethodgetDeclaredMethod(String name, 类<?>... parameterTypes)返回一个指定的 方法对象。参数(获取方法的名称,获取方法的形参列表)
Method[]getDeclaredMethods()返回包含一个数组 方法对象反射的类或接口的所有声明的方法,通过此表示 对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。
FieldgetField(String name)返回一个指定的运行时类中公共的指定变量名的Field对象
Field[]getFields()返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 对象。
StringgetName()返回由 对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String
intgetModifiers()返回此类或接口的Java语言修饰符,以整数编码。(0-default、1-public、2-private)
StringgetTypeName()为此类型的名称返回一个内容丰富的字符串。
class<?>[]getInterfaces()确定由该对象表示的类或接口实现的接口。
MethodgetMethod(String name, class<?>... parameterTypes)返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 对象。
Method[]getMethods()返回包含一个数组 方法对象反射由此表示的类或接口的所有公共方法 对象,包括那些由类或接口和那些从超类和超接口继承的声明。
intgetModifiers()返回此类或接口的Java语言修饰符,以整数编码。
StringgetName()返回由 对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String
Object[]getSigners()获得这个类的签名者。
StringgetTypeName()为此类型的名称返回一个内容丰富的字符串。
TnewInstance()创建由此 对象表示的类的新实例。
StringtoString()将对象转换为字符串。

Method类(方法)

Modifier and TypeMethod and Description
booleanequals(Object obj)将此 方法与指定对象进行比较。
Annotation[]getDeclaredAnnotations()返回 直接存在于此元素上的注释。
intgetModifiers()返回由该对象表示的可执行文件的Java语言修饰符,作为整数。(0-default、1-public、2-private、4-protected)
StringgetName()返回由此 方法对象表示的方法的名称,作为 String
booleanisAccessible()获取此对象的 accessible标志的值。
Objectinvoke(Object obj, Object... args)在具有指定参数 方法对象上调用此 方法对象的方法。
voidsetAccessible(boolean flag)将此对象的 accessible标志设置为指示的布尔值。
StringtoString()返回一个描述这个 方法的字符串。

Field类(属性)

Modifier and TypeMethod and Description
booleanequals(Object obj)将此 方法与指定对象进行比较。
Objectget(Object obj)返回该所表示的字段的值 Field ,指定的对象上。
Annotation[]getDeclaredAnnotations()返回 直接存在于此元素上的注释。
intgetModifiers()返回由该 Field对象表示的字段的Java语言修饰符,作为整数。(0-default、1-public、2-private、4-protected)
StringgetName()返回由此 Field对象表示的字段的名称。
Class<?>getType()返回一个 对象标识了此表示的字段的声明类型 Field对象。
booleanisAccessible()获取此对象的 accessible标志的值。
voidsetAccessible(boolean flag)将此对象的 accessible标志设置为指示的布尔值。
voidset(Object obj, Object value)obj对象参数上的此 Field对象表示的字段设置为指定的新值。
StringtoString()返回一个描述这个 Field的字符串。

Constructor(构造器)

Modifier and TypeMethod and Description
booleanequals(Object obj)将此 Constructor与指定对象进行比较。
intgetModifiers()返回由该对象表示的可执行文件的Java语言修饰符,作为整数。(0-default、1-public、2-private、4-protected)
StringgetName()以字符串形式返回此构造函数的名称。
intgetParameterCount()返回由此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明)的数量。
类<?>[]getParameterTypes()返回一个 对象的数组, 以声明顺序表示由该对象表示的可执行文件的形式参数类型。
TnewInstance(Object... initargs)使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
StringtoString()返回一个描述这个 Constructor的字符串。

反射相关操作手把手教学

package reflecttest;

public class Person {
	public int age;
	private String name;
	
	public Person() {
		// TODO 自动生成的构造函数存根
	}
	
	public Person(String name) {
		super();
		this.name = name;
	}
	
	private Person(String name,int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public int getAge() {
		return age;
	}

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

	public String getName() {
		return name;
	}

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

	public void show(String name,int age) {
		System.out.println("迪迦,变身");
	}
    
   private void fly() {
		System.out.println("迪迦,飞行");
	}
    
   private String Work(String name,int age) {
		return name;	
	}

}

获取Class的实例的三种方式

Class的实例就是运行时的类

  1. 通过类字面常量Class.class获取

    		Class clazz = Person.class;
    
  2. 通过Object类中的getClass()方法返回一个Class类型的实例

    		Person person = new Person();
    		Class clazz = person.getClass();
    
  3. 通过静态方法Class.forName("全类名")获取类名对应的Class对象

    		Class clazz = Class.forName("reflecttest.Person");
    

通过反射创建对象

反射创建类对象主要有两种方式,通过Class对象的newInstance()方法、通过Constructor对象的 newInstance()方法。

  1. 第一种:通过Class对象的newInstance()方法。

    		// 获取类的 Class 对象实例
    		Class clazz = Person.class;
    
    		//创建Person对象
    		Person person = (Person)clazz.newInstance();
    
  2. 第二种:通过Constructor对象的newInstance()方法

    		// 获取类的 Class 对象实例
    		Class clazz = Person.class;
    
    		//创建Person对象
    		Constructor constructor = clazz.getConstructor();
    		Person person = (Person)constructor.newInstance();
    

通过Constructor对象创建类对象可以选择特定构造方法,而通过 Class对象则只能使用默认的无参数构造方法。

示例:(调用有参构造方法进行类对象的初始化)

		// 获取类的 Class 对象实例
		Class clazz = Person.class;
		
		//创建Person对象
		Constructor constructor = clazz.getConstructor();
		Person person = (Person) constructor.newInstance("迪迦",16);

通过反射调用对象属性

获取属性

获取所有属性的两种方式
  1. getFields()

    		// 通过getFields()获取Person.class及父类中所有 public 修饰的属性
    		Field[] fields = clazz.getFields();
    
  2. getDeclaredFields()

    		// 通过getDeclaredFields()获取Person.class中所有的属性
    		Field[] fields = clazz.getDeclaredFields();	
    

注:

getFields()可以获取本类及父类中所有 public 修饰的属性
getDeclaredFields()可以获取本类所有的属性。包括 public、private、protected、default 修饰的属性,不包括父类中的属性

获取指定属性的两种方式
  1. getField(String name)

    		// 通过getField()获取Person.class中的age属性		
    		Field field = clazz.getField("age");
    
  2. getDeclaredField(String name)

    		// 通过getDeclaredField()获取Person.class中的name属性
    		Field field = clazz.getDeclaredField("name");	
    

注:

getField(String name) 可以获取本类及父类中的 public 修饰的属性
getDeclaredField(String name)可以获取本类的属性。包括 public、private、protected、default 修饰的属性,不包括父类中的属性

对属性的操作

设置属性值
		// 通过getDeclaredField()获取Person.class中的name属性
		Field field = clazz.getDeclaredField("name");

		//如果属性是private修饰的,则需要设置访问权限才能赋值
		field.setAccessible(true);

		//通过set(Object obj, Object value)设置person对象的name属性为"迪迦"
		field.set(person, "迪迦");

注:如果属性是private修饰的,则需要设置setAccessible(true)才能赋值

获取属性值
		//通过get(Object obj)获取person对象的field属性
		String name = (String) field.get(person);
获取属性的类型
		//通过getType()获取属性的类型
		Class type = field.getType();

		//获取属性的类型名
		String typename = field.getType().getName();
获取属性名
		//调用getName()获取属性名
		String fieldname = field.getName();
获取修饰类型
		//调用getModifiers()获取修饰类型,
		int modifier = field.getModifiers();

		//Modifier.toString(int mod)转成public、private、protected、default
		String modifiername = Modifier.toString(modifier);

注:0-default、1-public、2-private、4-protected

示例

		// 获取类的 Class 对象实例
		Class clazz = Person.class;
		
		//创建Person对象
		Person person = (Person) clazz.newInstance();
		
		// 通过getDeclaredField()获取Person.class中的name属性
		Field field = clazz.getDeclaredField("age");	
		field.setAccessible(true);
		//通过set()设置person对象的age属性为"12"
		field.set(person, 12);	
		
		//获取修饰符
		int modifier = field.getModifiers();
		String modifiername = Modifier.toString(modifier);
		//获取属性类型名
		String typename = field.getType().getName();
		//获取属性名
		String fieldname = field.getName();
		//获取属性值
		int fieldvalue = field.getInt(person);

		System.out.println(modifiername+" "+typename+" "+fieldname+" = "+fieldvalue+";");
		

输出:public int age = 12;

通过反射调用对象方法

获取方法

获取所有方法的两种方式
  1. getMethods()

    		//通过getMethods()获取Person类及父类中所有的public修饰的方法		
    		Method[] methods =clazz.getMethods();
    
  2. getDeclaredMethods()

    		//通过getDeclaredMethods()获取Person类中所有的方法
    		Method[] methods = clazz.getDeclaredMethods();
    

注:

getMethods()可以获取本类及父类中所有 public 修饰的方法
getDeclaredMethods()可以获取本类所有的方法。包括 public、private、protected、default 修饰的方法,不包括父类中的方法

取指定方法的两种方式

用方法名和形参列表来确定获取的方法

  1. getMethod(String name, class<?>... parameterTypes)

    		//获取Person类中的show方法,参数为方法名,show()的形参列表
    		Method method =clazz.getMethod("show",String.class,int.class);
    
  2. getDeclaredMethod(String name, 类<?>... parameterTypes)

    		//获取Person类中的fly方法,参数为方法名,fly()无形参列表
    		Method method = clazz.getDeclaredMethod("fly");
    

注:

getMethod() 可以获取本类及父类中的 public 修饰的属性
getDeclaredMethod()可以获取本类的属性。包括 public、private、protected、default 修饰的属性,不包括父类中的属性

对方法的操作

调用方法
		//获取Person类中的fly方法,参数为方法名,fly()无形参列表
		Method method = clazz.getDeclaredMethod("fly");

		//如果方法是private修饰的,则需要设置访问权限
		method.setAccessible(true);

		//调用person中的fly方法
		method.invoke(person);
		//如果方法是静态方法static时,除了上面的方式,也可用下面的方法,当前类调用方法
		//method.invoke(Person.class);

注:invoke()方法的返回值和调用的方法的返回值一样

获取方法的参数列表
		//获取形参列表
		Class[] paramTypes =method.getParameterTypes();	
获取方法名
		//获取方法名
		String methodname = method.getName();
获取方法的修饰类型
		//获取方法修饰符
		int modifier = method.getModifiers();
		String modifiername = Modifier.toString(modifier);
获取方法的返回值类型
		//获取返回值类型
		Class<?> returntype =method.getReturnType();

		//获取返回值类型名
		String returntypename = returntype.getName();

示例

	public static void main(String[] args) throws Exception, IllegalAccessException {
		// 获取类的 Class 对象实例
		Class clazz = Person.class;
		
		//创建Person对象
		Person person = (Person) clazz.newInstance();
		
		//获取Person类中的方法
		Method method = clazz.getDeclaredMethod("Work",String.class,int.class);
		
		//设置权限
		method.setAccessible(true);
		
		//获取方法名
		String methodname = method.getName();
		
		//获取方法修饰符
		int modifier = method.getModifiers();
		String modifiername = Modifier.toString(modifier);
		
		//获取返回值类型
		Class<?> returntype =method.getReturnType();		
		//获取返回值类型名
		String returntypename = returntype.getName();
		
		//获取形参列表
		Class[] paramTypes =method.getParameterTypes();	
		
		System.out.print(modifiername+" "+returntypename+" "+methodname+"(");
		
		//打印方法参数
		printParamTypes(paramTypes);
			
	}
    /**
     * 打印方法参数
     * @param paramTypes
     */
    private static void printParamTypes(Class[] paramTypes) {
        for (int j = 0; j < paramTypes.length; ++j) {
            if (j > 0) {
                System.out.print(",");
            }
            System.out.print(paramTypes[j].getName());
        }
        System.out.println(");");
    }

输出:private java.lang.String Work(java.lang.String,int);


通过反射调用对象构造方法

获取构造方法

获取所有构造方法的两种方式
  1. getConstructors()

    		//获取所有public修饰的构造方法,不包括父类
    		Constructor[] constructors = clazz.getConstructors();
    
  2. getDeclaredConstructors()

    		//获取所有构造方法,包括public、private、protected、default 修饰,不包括父类
    		Constructor[] constructors = getDeclaredConstructors();
    

注:

getConstructors()可以获取本类中所有 public 修饰的构造方法,不包括父类
getgetDeclaredConstructors()可以获取本类所有的构造方法。包括 public、private、protected、default 修饰的方法,不包括父类

获取指定构造方法的两种方式

对构造器的选择是依赖于形参列表的类型

  1. clazz.getConstructor()

    		//获取无参数的构造方法
    		Constructor constructor = clazz.getConstructor();
    
  2. getDeclaredConstructor()

    		//获取形参为(String,int)类型的构造方法
    		Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
    

注:

getConstructor()只可以获取本类 public 修饰的构造方法,不包括父类
getDeclaredConstructor()可以获取本类所有的构造方法。包括 public、private、protected、default 修饰的方法,不包括父类

对构造方法的操作

创建对象

对构造器的选择是依赖于形参列表的类型

		//获取空参的构造器
		//Constructor constructor = clazz.getDeclaredConstructor();
		Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
	
		//如果构造方法是private修饰的,设置权限
		constructor.setAccessible(true);
		
		//创建person对象
		Person person = (Person)constructor.newInstance("迪迦",20);
获取构造方法的参数列表
		//获取构造方法形参列表
		Class[] paramTypes = constructor.getParameterTypes();
获取构造方法名
		//获取构造方法名
		String constructorname = constructor.getName();
获取构造方法的修饰类型
		//获取构造方法的修饰符
		int modifier = constructor.getModifiers();
		String modifiername = Modifier.toString(modifier);

示例

public static void main(String[] args) throws Exception, IllegalAccessException {
		// 获取类的 Class 对象实例
		Class clazz = Person.class;

		//获取带参的构造器
		Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
	
		//如果构造方法是private修饰的,设置权限
		constructor.setAccessible(true);
		
		//创建person对象
		Person person = (Person)constructor.newInstance("迪迦",20);
		
		//获取构造方法名
		String constructorname = constructor.getName();
		
		//获取构造方法的修饰符
		int modifier = constructor.getModifiers();
		String modifiername = Modifier.toString(modifier);
		
		//获取构造方法形参列表
		Class[] paramTypes = constructor.getParameterTypes();
		
		System.out.print(modifiername+" "+constructorname+"(");
		
		//打印方法参数
		printParamTypes(paramTypes);
		
	}
    /**
     * 打印方法参数
     * @param paramTypes
     */
    private static void printParamTypes(Class[] paramTypes) {
        for (int j = 0; j < paramTypes.length; ++j) {
            if (j > 0) {
                System.out.print(",");
            }
            System.out.print(paramTypes[j].getName());
        }
        System.out.println(");");
    }

输出:private test1.Person(java.lang.String,int);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@赵士杰

如果对你有用,可以进行打赏,感

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值