Java反射机制

为什么要使用反射?举个例子,程序在运行时接收到外部传入的一个对象,该对象的编译时类型是Object,但程序又需要调用该对象运行时类型的方法,编译时根本无法预知该对象和类可能属于哪些类,程序只能依靠运行时信息来发现该对象和类的真实信息,这时候就必须使用反射。

Java反射机制主要提供了以下功能:

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

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

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

在运行时调用任意一个对象的方法,包括private修饰的方法

Java反射所需要的类并不多,主要有java.lang.Class类,Java.lang.reflect包中的FieldConstructorMethodArray类,这里简单挑几个介绍一下。


1.Class

ClassReflection反射机制的起源,想要操作类的属性和方法,就必须从获取Class 对象开始,获取Class对象途径:

1)使用类的class属性:

Class<java.util.Date> clz1 = java.util.Date.class;

2)通过Class类中的静态方法forName(String className),传入类的全限定名(必须添加完整包名)

Class<?> clz3 = Class.forName(“java.util.Date”);

3)通过对象的getClass方法来实现,其中,getClass()Object类中的方法,所有的对象都可以调用该方法

java.util.Date str = new java.util.Date();

Class<?> clz2 = str.getClass();


2.Constructor

Constructor:表示类中构造器的类型,Constructor的实例就是某一个类中的某一个构造器

Class类获取构造器方法:

public Constructor<?>[] getConstructors():

该方法只能获取当前Class所表示类的public修饰的构造器

public Constructor<?>[] getDeclaredConstructors():

获取当前Class所表示类的所有的构造器,和访问权限无关

public Constructor<T> getConstructor(Class<?>... parameterTypes) :

获取当前Class所表示类中指定的一个public的构造器

参数:parameterTypes表示:构造器参数的Class类型

 

Constructor常用方法:

public T newInstance(Object... initargs):如调用带参数的构造器,只能使用该方式.

     参数:initargs:表示调用构造器的实际参数

     返回:返回创建的实例,T表示Class所表示类的类型

 

如果一个类中的构造器是外界可以直接访问,同时没有参数.,那么可以直接使用Class类中的newInstance方法创建对象.

 public Object newInstance():相当于new 类名();

 

调用私有的构造器:

访问私有的成员的时候,必须先设置可访问的:

对象.setAccessible(true);

调用私有构造器也一样,要先设置可访问:

构造器对象.setAccessible(true);

 

总的来说,使用反射创建对象的步骤如下:

    1);找到构造器所在类的字节码对象,即上述的Class对象.

    2):获取构造器对象.

    3):使用反射,创建对象

 

3.Method

使用反射获取类中的方法:

1):获取方法所在类的字节码对象.

2):获取方法.

 

Class类中获取Method的常用方法:

1public Method[] getMethods():获取包括自身和继承过来的所有的public方法

2public Method[] getDeclaredMethods():获取自身类中所有的方法(不包括继承的,和访问权限无关)

 

3public Method getMethod(String methodName,Class<?>... parameterTypes):表示调用指定的一个公共的方法(包括继承的)

       参数:

               methodName: 表示被调用方法的名字

               parameterTypes:表示被调用方法的参数的Class类型如String.class

 

4public Method getDeclaredMethod(String name,Class<?>... parameterTypes):表示调用指定的一个本类中的方法(不包括继承的)

        参数:

               methodName: 表示被调用方法的名字

               parameterTypes:表示被调用方法的参数的Class类型如String.class

 

使用反射调用方法的步骤:

1):获取方法所在类的字节码对象.

2):获取方法对象.

3):使用反射调用方法.

 

如何使用反射调用一个方法:

Method类中有这样一个方法可以实现这个功能:

public Object invoke(Object obj,Object... args):表示调用当前Method所表示的方法

      参数:

            obj: 表示被调用方法底层所属对象

                 Method m = clz.getMethod("sayHi",String.class);

            args:表示调用方法是传递的实际参数

      返回:

            底层方法的返回结果

 

如果是要调用私有方法,在调用之前要设置该方法为可访问的:

Method对象.setAccessible(true);

 

扩展:

1)使用反射调用静态方法:

   静态方法不属于任何对象,静态方法属于类本身.

   此时把invoke方法的第一个参数设置为null即可.




2)使用反射调用数组参数(可变参数):

   调用方法的时候把实际参数统统作为Object数组的元素即可.

   Method对象.invoke(方法底层所属对象,new Object[]{  所有实参   });

class Student{
	public static void doWork1(int... arr ){
		System.out.println("doWork1方法被调用"+Arrays.toString(arr));
	}
	
	public static void doWork2(String...strings){
		System.out.println("doWork2被调用"+Arrays.toString(strings));
	}
}

//使用反射调用数组参数(可变参数):
public class MethodInvokeDemo {
	public static void main(String[] args) throws Exception {
		Class<?> clz1 = Student.class;
		//情况1:数组的元素类型是基本类型
		Method m = clz1.getMethod("doWork1", int[].class);
		//m.invoke(null, 1,2,3,4,5);//错误
		System.out.println(m);
		//m.invoke(null, new int[]{1,2,3,4,5,6});//正确,也可以改成下面的
		m.invoke(null, new Object[]{new int[]{1,2,3,4,5,6}});//正确
		
		//情况2:数组的元素类型是引用类型
		m = clz1.getMethod("doWork2",String[].class);
		//m.invoke(clz1.newInstance(),  new String[]{"A","b","C"});报下面的异常
		//java.lang.IllegalArgumentException: wrong number of arguments
		m.invoke(clz1.newInstance(), new Object[]{new String[]{"A","b","C"}});//正确
	}

}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值